try-with-resources

try 블록이 끝날 때 선언한 자원의 close()를 자동으로 호출해 자원 누수를 막아주는 Java 7의 문법입니다.

사용 조건

try (BufferedReader br = new BufferedReader(new FileReader("path"))) {
    return br.readLine();
} catch (IOException e) {
    return null;
}

InputStream, OutputStream, Connection, Statement, ResultSet 등 JDK가 제공하는 대부분의 자원 클래스는 이미 AutoCloseable을 구현하고 있습니다.

왜 try-catch-finally 대신 쓰는가

기존 방식은 finally에서 close()를 직접 호출해야 합니다.

BufferedReader br = null;
try {
    br = new BufferedReader(new FileReader("path"));
    return br.readLine();
} catch (IOException e) {
    return null;
} finally {
    if (br != null) {
        try {
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

try-with-resources는 이 문제를 문법 차원에서 해결합니다.

// out이 먼저 닫히고, 그다음 in이 닫힌다
try (InputStream in = new FileInputStream("src");
     OutputStream out = new FileOutputStream("dst")) {
    in.transferTo(out);
}

Suppressed Exception (억제된 예외)

try 블록의 예외와 close()의 예외가 동시에 발생하면, try 블록에서 발생한 원래 예외(Primary Exception) 가 전파되고 close()의 예외는 그 예외에 억제된 예외로 첨부됩니다.

class CustomResource implements AutoCloseable {

    @Override
    public void close() throws Exception {
        throw new Exception("Close Exception 발생");
    }

    void process() throws Exception {
        throw new Exception("Primary Exception 발생");
    }
}
Exception in thread "main" java.lang.Exception: Primary Exception 발생
    at CustomResource.process(CustomResource.java:9)
    at Main.main(Main.java:5)
    Suppressed: java.lang.Exception: Close Exception 발생
        at CustomResource.close(CustomResource.java:5)
        at Main.main(Main.java:4)

반면 try-catch-finally에서는 finally의 close() 예외가 원래 예외를 덮어써서 진짜 원인이 스택 트레이스에서 사라집니다. Throwable.addSuppressed()로 직접 처리할 수도 있지만 코드가 복잡해지므로 try-with-resources에 맡기는 편이 낫습니다. 억제된 예외는 Throwable.getSuppressed()로 조회할 수 있습니다.

주의사항

핵심 정리

→ try-with-resources에 대해 설명해 주세요

CSLOG에서 보기