본문 바로가기

Java

[Effective Java] 아이템9. try-finally보다는 try-with-resources 사용하라

자바 라이브러리에서는 close()로 직접 닫아야 하는 자원이 있다.

ex: InputStream, OutputStream, java.sql.Connectioin

 

자원닫기는 클라이언트가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어질 수 있다.

 

자원반납시 try-finally의 결점

자원이 제대로 닫힘을 보장하는 수단으로 try-finally를 사용했다.

자바 InputStream 기본 예제로 finally문에서 close하는 예제를 많이 봤을 것이당

static String firstLineOfFile(String path) throws IOException {
        final BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
        try {
            return bufferedReader.readLine();
        }finally {
            bufferedReader.close();
        }
}

이와 같이 finally에서 close()를 하면, finally는 try문 후에 무조건 실행되므로 반드시 자원이 반납됨이 보장된다.

 

하지만 try, finally문에서 둘 다 예외가 발생할 수 있다!!

위 예제에서 readLine()에서 예외가 발생했다면 finally블록의 close()또한 실패할 것이다.

close()예외가 먼저 발생한 readLine()예외를 집어 삼켜

readLine() 예외에 대한 정보는 남지 않게되고, 디버깅이 어려워진다.

 

 

try-with-resources

전제조건: 자원이 AutoClosable인터페이스를 구현해야 한다.

 

public interface AutoCloseable {
    void close() throws Exception;
}

AutoClosable은 위처럼 void를 반환하는 close()만을 정의한 인터페이스이다.

 

 

try-with-resources를 사용하면 자동으로 자원을 반납한다. 

static String firstLineOfFile(String path, String defaultVal) throws IOException {
        final BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
        try {
            return bufferedReader.readLine();
        }catch (IOException ioException){
            return defaultVal;
        }
}

또한 catch절을 사용해서 다수의 예외를 처리할 수 있다. 

catch절을 이용하지 않았을 경우에는 close()예외는 숨겨지고 readLine()에서 발생한 예외만 기록되는데,

숨겨진 예외도 스택 추적 내역에서 확인할 수 있다. (suppressed를 달고 출력됨)

또한 자바 7에서 Throwable에 추가된 getSuppressed()메서드로도 가져올 수 있다.