use
API を使用して、使用が完了した resource を閉じましょう。
私たちが使用するリソースの中には、使用完了後に使用状態を停止に変えないものがあります。そして、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 でリソースをハンドリングすることは、コードが時として複雑になり、汚くなります。そのためにサポートされている機能が try with resources です。短く説明すると、try で使用したリソースを try ブロックが終了する時に自動的に Close 処理してくれます。
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();
}
}