携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
有些资源在不再需要时必须使用 close() 显式关闭。
- 输入/输出流
- java.sql.Connection
- java.io.Reader(FileReader, BufferedReader, CSSParser)
- java.new.socket,java.util.Scanner
这些资源都是实现了继承 AutoCloseable 的 Closeable 接口。
当对资源的引用丢失时,所有这些资源最终都由垃圾收集器处理,但同时维护资源非常缓慢且成本高昂。因此,最好在不再需要时显式调用 close()。
传统上,这些资源是使用try-catch 块处理的。
fun countCharactersInFile(path: String): Int {
val reader = BufferedReader(FileReader(path))
try {
return reader.lineSequence().sumBy {it.length}
} finally {
reader.close()
}
}
这种代码既复杂又糟糕。 关闭资源时可能会出现异常,因为此类异常没有单独处理。
此外,如果在 try 块或 finally 块中发生错误,则只会传播其中一个。如果两者都可以传播,那就太好了,但是自己实现这一点将是漫长而复杂的。但是,由于它是一种被广泛使用的通用实现,因此它作为一个名为 use 的函数包含在标准库中。
如果使用 use() 更改之前的代码,如下所示。
fun countCharactersInFile(path: String): Int {
val reader = BufferedReader(FileReader(path))
reader.use {
return reader.lineSequence().sumBy { it.length }
}
}
还有一种形式是接收器(当前代码中的读取器)作为 lambda 参数传递,因此可以简写如下
fun countCharactersInFile(path: String): Int {
BufferedReader(FileReader(path)).use {
return reader.lineSequence().sumBy { it.length }
}
}
因为文件经常被写成资源并且文件经常被逐行读取,所以 Kotlin 标准库还提供了 useLines() 可以用来逐行处理文件。
fun countCharactersInFile(path: String): Int {
File(path).useLines { lines ->
return lines.sumBy { it.length }
}
}
这种处理方式将文件内容逐行保存在内存中,因此可以对大文件进行适当的处理,但缺点是文件的行只能写入一次。如果要多次迭代文件中的特定行,则需要多次打开文件。前面的代码可以简单地写成如下。
fun countCharactersInFile(path: String): Int = File(path).useLines { lines -> lines.sumBy { it.length } }