使用 use api 关闭已完成使用的资源
在我们使用的资源中,有些资源在使用完成后不会自动停止状态。我们需要通过 close 方法等将这些资源的状态更改为未使用状态。
Kotlin/JVM 中使用的 Java 标准库包含了许多此类资源。以下是典型的不会自动释放的资源:
- InputStream and OutputStream
- Java.sql.Connection
- Java.io.Reader ( FileReader, BufferedReader, CSSParser )
- Java.new.Socket and java.util.Scanner
所有这些资源都支持继承自 AutoCloseable 的 Closeable 接口。
请查看以下代码片段:
fun countCharactersInFile(path:String):Int{
val reader = BufferedReader(FileReader(path))
try {
return reader.lineSequence().sumBy { it.length }
}
finally {
reader.close()
}
}
上面的代码既复杂又不严谨。因为如果 finally 块中的 reader.close() 抛出异常,则无法处理。如果要处理这种情况,代码可能会变成这样:
fun countCharactersInFile(path:String):Int{
val reader = BufferedReader(FileReader(path))
try {
return reader.lineSequence().sumBy { it.length }
}
finally {
try { reader.close() } catch (e: Exception) {}
}
}
这种实现方式既冗长又复杂,但由于它是通用做法,因此被提取到了标准库函数 use 中。该功能从 Kotlin 1.2 版本开始支持。
以下是参考书中的示例以及补充示例。
try {
Socket("open", 80).use { socket ->
socket.getInputStream().use { inputStream ->
InputStreamReader(inputStream).use { reader ->
println(reader.readLines())
}
}
}
} catch (e: Exception) {
// ...
}
使用 use 时,如果存在嵌套情况,使用默认的 it 可能会产生问题,因此建议根据作用域明确声明变量名后再使用。
try-with-resources
我们习惯使用的 try-catch 处理资源的方式有时会使代码变得复杂且混乱。为此,Java 提供了 try-with-resources 功能。简而言之,它会在 try 块结束时自动关闭在该 try 中使用的资源。
public static String getHtml(String url) throws IOException {
val targetUrl = URL(url);
try (val inputSR = new InputStreamReader(targetUrl.openStream());val bufferReader = BufferedReader(inputSR)){
val html = StringBuffer();
var tmp;
while ((tmp = reader.readLine()) != null) {
html.append(tmp);
}
return html.toString();
}
}