web-dev-qa-db-ja.com

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

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

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;
}
85
Cheetah

正しく、catch句の要件はありません。 Oracle Java 7 docは、リソースが閉じられると述べていますに関係なく例外が実際にスローされるかどうか。

catch句は、例外に対応したい場合にのみ使用してください。 catch句が実行されますafterリソースが閉じられます。

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のコードはcatchを実行し、その後finallyブロックを実行します。これにより、catchブロックでリソースが潜在的に開かれたままになります。

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

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

102
yair

この特定のケースでは、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は閉じられます。詳細は here および here をご覧ください。

69
Andrii Polunin