Effective Kotlin - 使用済みのリソースを閉じる

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();
    }
}

読んでおくと良いブログ記事

AD