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

안녕하세요. Cheetah, 저는 catchJava 6에 대한 첫 번째 예제 의 역할을 이해하려고합니다 . 즉 catch (Exception ex) { throw ex; }, 예외를 다시 던지는 것입니다. 아무 일도하지 않고 쉽게 제거 할 수 있습니다. 아니면 내가 뭔가를 놓치고 있습니까?
사샤

답변:


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 문이 정상적으로 완료되는지 갑작스럽게 완료되는지에 관계없이 닫힙니다 (IOException을 던지는 BufferedReader.readLine 메서드의 결과로).

편집하다

새로 수정 된 질문에 관하여 :

Java 6의 코드 catchfinally블록을 실행 하고 그 이후에 실행합니다 . 이로 인해 리소스가 catch블록 에서 여전히 잠재적으로 열립니다 .

자바 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))a IllegalArgumentException가 던져지는 경우 를 통해 생성 된 리소스 가 닫히지 않는 이유를 이해하려고합니다 . try-with-resources는 AutoClosablethrow 된 예외에 관계없이 모든 리소스를 닫지 않습니까?
Prasoon Joshi

3
@PrasoonJoshi 아니요, .close()try-with-resources 이니셜 라이저에서 선언 된 변수 만 호출 합니다. 이것이이 예제에서 두 개의 선언으로 분리하는 것이 트릭을 수행하는 이유입니다.
Mario Carneiro

4
Andrii와 @Mario 당신은 옳고 그름입니다. 첫 번째 예제에서 FileReader는 try-with-resource 논리에 의해 닫히지 않습니다. 그러나 BufferedReader가 닫히면 래핑 된 FileReader도 닫힙니다. 증명을 위해 java.io.BufferedReader.close ()의 소스를 살펴보십시오. 결과적으로 첫 번째 예제의 코드가 더 간결하기 때문에 선호되어야합니다.
jschreiner

7
@jschreiner True, sz < 0생성자가 예외 를 발생시키는 Andrii의 (다소 인위적인) 문제로 인해 실제로 리소스가 누출 될 수 있습니다.
Mario Carneiro 2016

5
@mario 동의합니다. 외부 생성자가 실패하고 내부 리소스가 유출 될 수 있습니다. 전에는 본 적이 없었습니다. 감사합니다.
jschreiner
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.