Book Record/Effective Java 3E

[Effective Java] try-finally 보다는 try-with-resources를 사용하라

lakelight 2022. 12. 1. 16:58
728x90
반응형

 

 

자바 라이브러리에는 close 메서드를 호출해 직접 닫아줘야 하는 자원이 많습니다.
InputStream, OutputStream 등이 좋은 예입니다.

자원 닫기는 클라이언트가 놓치기 쉬워 예측할 수 없는 성능 문제로 이어지기도 합니다.
전통적으로 자원이 제대로 닫힘을 보장하기 위해 try-finally를 사용했습니다.

 

try-finally 코드 예시

public class TryFinallyTest {
    static void copyFiles(String rawPath, String copyPath) throws IOException {
        InputStream in = new FileInputStream(rawPath);
        try{
            OutputStream out = new FileOutputStream(copyPath);
            try{
                byte[] buf = new byte[BUFFER_SIZE];
                int n;
                while((n=in.read(buf))>=0)
                    out.write(buf, 0, n);
            } finally {
                out.close();
            }
        } finally {
            in.close();
        }
    }
}
예외는 try블록과 finally블록 모두에서 발생할 수 있는데,  물리적인 문제가 발생한다면 copyFiles() 메서드 안의 in.read() 또는 out.write()에서 예외가 발생하고 close() 또한 예외를 발생시킬 것입니다. 그럴 경우 두번째 예외가 첫번째 예외를 집어 삼켜 버립니다. 그렇게 되면 첫번째 예외는 남지 않게 되는 문제가 생길 수 있습니다. 물론 코드를 통해 구현은 가능하지만 코드가 복잡해질 것입니다.

위와 같은 문제를 해결하기 위해 try-with-resources 구조가 나오게 되었습니다. 이 구조를 사용하기 위해서는 AutoCloseable 인터페이스를 구현해야하는데, 이는 단순히 void를 반환하는 close메서드 하나만 정의한 인터페이스입니다. 자바 라이브러리와 서드파티 라이브러리들의 수많은 클래스와 인터페이스가 이미AutoCloseable을 구현하거나 확장해두었습니다.
public class TryFinallyTest {
    static void copyFiles(String rawPath, String copyPath) throws IOException {
        try(InputStream in = new FileInputStream(rawPath);
            OutputStream out = new FileOutputStream(copyPath)){
            byte[] buf = new byte[BUFFER_SIZE];
            int n;
            while((n=in.read(buf))>=0)
                out.write(buf, 0, n);
        } catch (IOException e){
            e.printStackTrace();
        }
    }
}
try-with-resources 버전을 사용하기 코드가 짧고 읽기 수월할 뿐 아니라 문제를 진단하기도 좋아졌습니다. in.read(), out.write()와 close 호출 양쪽에서 예외가 발생하면, close에서 발생한 예외는 숨겨지고 in.read()나 out.write()에서 발생한 예외가 기록됩니다.
또한 숨겨진 예외들도 버려지지않고, 스택 추적 내역에 suppressed라는 꼬리표를 달고 출력합니다. 자바7에서는 Throwable에 추가된 getSuppressed 메서드를 이용하면 프로그램 코드에서 가져올 수도 있습니다.

 

마무리

회수해야 하는 자원이 있다면 꼭 try-with-resources를 사용해야 합니다.
예외는 없습니다. 코드는 더 짧고 분명해지고, 만들어지는 예외 정보도 훨씬 유용합니다.
try-with-resources를 이용하면 정확하고 쉽게 자원을 회수할 수 있습니다.

감사합니다.

 

 

 

[출처]

이펙티브 자바 Effective Java 3/E - 조슈아 블로크 저/ 개앞맵시 

 

728x90
반응형