Kotlin中如何从InputStream.forEachLine的Lambda中跳出循环
解决自定义InputStream.forEachLine扩展的循环提前终止问题
我完全懂你碰到的这个麻烦——自己写的forEachLine扩展里,想在Lambda满足条件时直接跳出整个循环,但试了好几种方法都没达到预期。核心问题在于你当前的扩展函数里,传入的Lambda是(String) -> Unit类型,它没办法给外层循环传递“停止继续执行”的信号。下面给你两种实用的解决方案:
方案1:通过Lambda返回值控制循环
我们可以修改扩展函数的Lambda类型,让它返回一个Boolean值:返回true就继续处理下一行,返回false就立即终止整个循环。这种方式不需要依赖inline特性,逻辑也很直观。
修改后的扩展函数代码:
fun InputStream.forEachLine(consumer: (line: String) -> Boolean) { val reader = BufferedReader(InputStreamReader(this, Charset.defaultCharset())) var line: String? = reader.readLine() while (line != null) { // 如果consumer返回false,直接终止循环 if (!consumer(line)) break line = reader.readLine() } }
对应的测试代码:
@Test fun testExtnInputStreamForEachLine() { val stream = FileInputStream(File("c:\\temp\\sometextfile.txt")) stream.forEachLine { line -> println(line) // 满足条件时返回false,终止整个forEachLine循环 if (line.equals("some text")) { return@forEachLine false } // 否则返回true,继续处理下一行 true } // 这里的代码会在forEachLine终止后正常执行 }
方案2:用inline函数支持非局部返回
如果你想贴近Kotlin标准库的使用习惯(比如标准库的forEachLine支持直接return终止),可以把你的扩展函数标记为inline。inline函数允许Lambda使用非局部返回,也就是直接用return跳出外层的forEachLine函数(注意:这种返回会直接跳出包含forEachLine的外层函数,比如这里的测试函数)。
修改后的扩展函数:
inline fun InputStream.forEachLine(consumer: (line: String) -> Unit) { val reader = BufferedReader(InputStreamReader(this, Charset.defaultCharset())) var line: String? = reader.readLine() while (line != null) { consumer(line) line = reader.readLine() } }
对应的测试代码:
@Test fun testExtnInputStreamForEachLine() { val stream = FileInputStream(File("c:\\temp\\sometextfile.txt")) stream.forEachLine { line -> println(line) if (line.equals("some text")) { // 直接跳出整个forEachLine和外层的测试函数 return } } // 这里的代码不会执行,因为上面的return已经跳出了测试函数 }
两种方案的选择建议
- 如果你需要在终止
forEachLine后继续执行外层函数的其他逻辑,优先选方案1; - 如果你的场景允许直接跳出外层函数,或者想和标准库API的用法保持一致,选方案2。
内容的提问来源于stack exchange,提问作者Manish Bansal
相关产品推荐
相关产品推荐

