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

2022년 03월 12일

TOC

이 글은 Effective Java 3/E의 내용을 요약한 글입니다. 자세한 내용은 책을 참고하시기 바랍니다.

try-finally와 try-with-resources의 차이

InputStream, OutPutStream, java.sql.Connection과 같은 자원들은 사용 후에 close()메서드를 통해 닫아줘야 합니다. 이는 실제로 클라이언트가 놓치기 쉬워 예측하기 어려운 성능 문제로 이어지기도 합니다.

finalizer는 믿음직하지 못하여 사용을 지양하는 것이 좋다.(이펙티브자바 아이템 7)

자원회수를 위한 전통적인 코드로는 많은 프로그래머들이 아래의 코드와 같이 try-finally를 사용하였다.

static String firstLiseOfFile(String path) throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        br.close();
    }
}

하지만 try-finally를 올바르게 사용하여도 미묘한 결점들이 존재합니다. 예시 코드가 물리적인 오류로 인해 try문에 위치한 return br.readLine();와 finally에 위치한 br.close();가 모두 실패한다 생각해보자, 이와같이 두번의 예외가 발생하게 된다면 두번쨰 예외가 처번째 예외를 완전히 삼켜먹어 디버깅을 어렵게 할 것입니다. 물론 여기서도 두번째 예외 대신 첫번째 예외가 나오게 코드를 수정할 수는 있지만 코드가 지저분해져서 좋지 않은 방법입니다.

이러한 문제들은 자바 7에서 나온 try-with-resources를 통해 해결할 수 있습니다.

해당 구조를 사용하려면 void를 반환하는 close()메서드 하나만 정의되어있는 AutoCloseable인터페이스를 구현해야합니다. 수많은 자바 라이브러리들은 이미 AutoCloseable를 구현하거나 확장하였습니다. 개발을 하며 닫아야 하는 자원 클래스를 생성한다면 AutoCloseable인터페이스를 구현하길 바랍니다.

static String firstLiseOfFile(String path) throws IOException {
    try (BufferedReader reader = new BufferedReader(new FileReader(path));) {
        return br.readLine();
    }
}

try-with-resources를 적용한 코드는 위와 같습니다. 해당 코드는 위의 try-finally로 구현한 코드와 비교하였을 때 코드도 짧아져 가독성이 좋아졌습니다. 또한 앞에서 설명했던 return br.readLine();br.close();에서 예외가 발생하는 상황만 생각해도 close()의 예외는 숨겨지고 br.readLine();의 예외만 기록되어 문제를 진단하기 쉽습니다.

close()와 같이 숨겨진 예외들은 버려지는 것은 아니고 "숨겨졌다.(suppressed)"라는 꼬리표를 달고 출력됩니다.

핵심정리

꼭 회수해야하는 자원을 다룰 때는 예외 상황 없이 try-finally말고, try-with-resources를 사용하도록 하자. try-with-resources를 사용하면 코드는 더 짧고 분명해지며, 만들어지는 예외 정보도 훨씬 유용하다. 또한 정확하고 쉽게 자원을 회수할 수도 있다.

Buy me a coffeeBuy me a coffee
Written by

@Seongwon

기술공유를 통해 새로운 가치 창조을 추구하는 백엔드 개발자 오성원입니다.
©SeongwonOh