Kotlin中遍历next函数返回有限值的可行模式探究
部分编程语言中存在一种常见模式:调用某函数时会返回序列的下一个值,直至有限序列结束,之后持续返回null。比如Java里的BufferedReader.readLine()、ZipInputStream.getNextEntry()都属于这类"next函数"——它们没有单独的hasNext()方法,仅通过返回null标记序列结束。
Java允许将赋值作为表达式,能写出(line = reader.readLine()) != null这样的循环条件,但Kotlin中赋值并非表达式,无法直接套用该写法。以下是几种在Kotlin中遍历这类函数返回值的可行模式,可按需选择:
1. 传统While循环(最直观)
先获取第一个值,进入循环处理后再更新值,逻辑清晰,无额外封装成本。
fun printAll(reader: BufferedReader) { var line = reader.readLine() while (line != null) { println(line) line = reader.readLine() } }
适用场景:简单单次遍历场景,代码可读性高,无需复用逻辑。
2. Do-While循环
先执行一次取值操作,再判断是否继续循环,适合逻辑上必须先执行一次取值的场景,但需注意空值处理避免无效操作。
fun printAll(reader: BufferedReader) { var line: String? do { line = reader.readLine() line?.let { println(it) } // 仅当非空时执行操作 } while (line != null) }
适用场景:需要确保至少执行一次取值的场景(比如某些资源初始化逻辑)。
3. 封装为Sequence序列
将next函数转换为Kotlin标准库的Sequence,可以利用函数式API进行链式操作(如filter、map),复用性强。
// 扩展函数,将BufferedReader转换为Sequence<String> fun BufferedReader.asLineSequence(): Sequence<String> = sequence { var line: String? do { line = readLine() line?.let { yield(it) } } while (line != null) } // 使用示例 fun printAll(reader: BufferedReader) { reader.asLineSequence() .filter { it.isNotBlank() } // 可添加函数式操作 .forEach { println(it) } }
适用场景:需要对序列进行多步处理、或多次复用遍历逻辑的场景。
4. 扩展函数封装forEach
直接给目标类添加遍历扩展函数,封装底层循环逻辑,调用时更简洁,符合Kotlin的语法风格。
// 扩展函数:直接遍历BufferedReader的所有行 fun BufferedReader.forEachLine(action: (String) -> Unit) { var line = readLine() while (line != null) { action(line) line = readLine() } } // 使用示例 fun printAll(reader: BufferedReader) { reader.forEachLine { println(it) } }
适用场景:项目中频繁需要遍历这类next函数的结果,封装后可统一调用逻辑,减少重复代码。
5. Repeat-Until循环(非常规)
利用repeat配合break跳出循环,逻辑不如前几种直观,仅作为特殊场景下的备选方案。
fun printAll(reader: BufferedReader) { var line: String? repeat(Int.MAX_VALUE) { line = reader.readLine() if (line == null) break println(line) } }
适用场景:需要与其他repeat逻辑配合的特殊场景,一般不推荐作为常规写法。
内容的提问来源于stack exchange,提问作者Devabc

