Java 7のtry-with-resourcesを正しく使用していますか


87

バッファリーダーとファイルリーダーが閉じ、例外がスローされた場合にリソースが解放されることを期待しています。

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
    try (BufferedReader br = new BufferedReader(new FileReader(filePath)))
    {
        return read(br);
    } 
}

ただし、catch閉鎖を成功させるための条項を設ける必要はありますか?

編集:

基本的に、Java 7の上記のコードは、Java 6の以下のコードと同等です。

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{

    BufferedReader br = null;

    try
    {
        br = new BufferedReader(new FileReader(filePath));

        return read(br);
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        try
        {
            if (br != null) br.close();
        }
        catch(Exception ex)
        {
        }
    }

    return null;
}

あなたの質問をもう一度読んだ後、私はそれをよく理解しているかどうかわかりません。説明していただけますか?
Maroun 2013

こんにちは。チーター、私はcatchJava 6の最初の例の役割を理解しようとしています。catch (Exception ex) { throw ex; }つまり、例外を再スローするだけで、何も実行せず、害を与えることなく簡単に削除できます。それとも何か不足していますか?
サーシャ2017

回答:


103

正解であり、catch条項の要件はありません。Oracle Java 7のドキュメントでは、例外が実際にスローされたかどうかに関係なく、リソースは閉じられると述べています。

catch例外に対応したい場合のみ句を使用する必要があります。このcatch句は、リソースが閉じられに実行されます。

以下は、Oracleのチュートリアルの抜粋です。

次の例では、ファイルから最初の行を読み取ります。BufferedReaderのインスタンスを使用して、ファイルからデータを読み取ります。BufferedReaderは、プログラムの終了後に閉じる必要があるリソースです。

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
} // In this example, the resource declared in the try-with-resources statement is a BufferedReader.

... BufferedReaderインスタンスはtry-with-resourceステートメントで宣言されているため、tryステートメントが正常に完了したか突然に完了したかに関係なく(メソッドBufferedReader.readLineがIOExceptionをスローした結果として)閉じられます。

編集

新しく編集された質問について:

Java 6のコードcatchfinallyブロックを実行し、その後ブロックを実行します。これにより、リソースがまだcatchブロックで開かれている可能性があります。

Java 7構文では、リソースはブロックのに閉じcatchられるため、リソースはcatchブロックの実行中にすでに閉じられています。これは上記のリンクに記載されています:

try-with-resourcesステートメントでは、宣言されたリソースが閉じられた後に、catchまたはfinallyブロックが実行されます。


69

この特定のケースでは、try-with-resourcesの使用は問題なく機能しますが、一般的には正しくありません。不愉快な驚きにつながる可能性があるため、そのようなリソースをチェーンしないでください。可変のバッファーサイズがあると仮定します。

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
    int sz = /* get buffer size somehow */
    try (BufferedReader br = new BufferedReader(new FileReader(filePath), sz))
    {
        return read(br);
    } 
}

何かがうまくいかなくて、あなたはsz否定的であったと仮定します。この場合、(で作成されたnew FileReader(filePath))ファイルリソースは閉じられません

この問題を回避するには、次のように各リソースを個別に指定する必要があります。

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
    int sz = /* get buffer size somehow */
    try (FileReader file = new FileReader(filePath);
         BufferedReader br = new BufferedReader(file, sz))
    {
        return read(br);
    } 
}

この場合、初期化にbr失敗してfileも、クローズされます。あなたはここここで詳細を見つけることができます。


で作成されたリソースが、szが負のときにがスローさnew FileReader(filePath))れた場合に閉じない理由を理解しようとしていIllegalArgumentExceptionます。AutoClosableスローされた例外に関係なく、try-with-resourcesはすべてのリソースを閉じませんか?
Prasoon Joshi、2015

3
@PrasoonJoshiいいえ、.close()try-with-resourcesイニシャライザで宣言された変数のみを呼び出します。これが、この例でそれを2つの宣言に分離するとうまくいく理由です。
Mario Carneiro、

4
Andriiと@Marioあなたはどちらも正しいと間違っています。最初の例では、FileReaderはtry-with-resourceロジックによって閉じられません。ただし、BufferedReaderを閉じると、ラップされたFileReaderも閉じられます。証拠として、java.io.BufferedReader.close()のソースを確認してください。結果として、最初の例のコードはより簡潔になるため、優先する必要があります。
jschreiner

7
@jschreiner True、ただしsz < 0、コンストラクターが例外をスローする原因となるAndriiの(多少の工夫)問題は、実際にはリソースのリークを引き起こします。
マリオカルネイロ

5
@mario同意する。外側のコンストラクターが失敗し、内側のリソースがリークする可能性があります。以前は見なかった、ありがとう。
jschreiner 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.