ITEM9 try-finally 보다는 try-with-resources를 사용하라
- 자바 라이브러리에는 close 메서드를 호출해 직접 닫아줘야 하는 자원이 많다.
- InputStream, OutputStream 등의 IO 라이브러리
- java.sql.Connection 등의 JDBC 사용을 위한 라이브러리

- 어떠한 이유(오류 또는 개발자의 실수)에 의해서 close가 안되면, 프로그램에 문제가 생길 수 있다.
- 이런 자원의 상당수가 안전망으로 finalizer를 활용하고 있긴 하나, 그리 믿을만하지는 못하다.
자원의 닫힘을 보장해주는 수단 : try-finally
- try와 finally는 짝꿍으로 붙어다녀야 하며, try블록에서 예외가 나던/나지않던 finally 안의 구문은 실행된다.
static String firstLineOfFile(String path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { br.close(); } }
static void copy(String src, String dst) throws IOException { InputStream in = new FileInputStream(src); try { OutputStream out = new FileOutputStream(dst); 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(); } }
- 코드의 가독성이 너무 나쁘다. 자원이 100개가 되면 try-finally가 100개가 생긴다.
static String firstLineOfFile(String path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { br.close(); } }
- 특히 예외는 try 블록과 finally 블록 모두에서 발생할 수 있는데, 위 예시에서 기기에 문제가 생기는 경우
- readLine 메서드가 먼저 예외를 던진다 : 파일을 읽을 수 없습니다.
- 그 다음 close 메서드가 예외를 던진다 : 파일을 close 할 수 없습니다.
→ 이런 상황이 발생하면 스택 추적 내역에 첫번째 예외에 관한 정보는 남지 않는다 : 디버깅이 어려워짐

해결책의 등장 : try-with-resources
- try 안에 파라미터로 자원을 넘겨주는 방식
- try 문에서 선언된 객체들에 대해서 try가 종료될 때 자동으로 자원을 해제해주는 기능이 있다.
- 먼저 이 구조를 사용하려면 해당 자원이 AutoCloseable 인터페이스를 구현해야 한다.
- AutoCloseable 인터페이스 : void 타입의 close 메서드 하나만 덩그러니 정의된 인터페이스
public interface AutoCloseable { void close() throws Exception; }
Closeable?
public abstract class BufferedReader implements AutoCloseable { ... }
static String firstLineOfFile(String path) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(path))) { return br.readLine(); } }
static void copy(String src, String dst) throws IOException { try (Input in = new FileInput(src); Output out = new FileOutput(dst)) { byte[] buf = new byte[BUFFER_SIZE]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } }
- 코드의 가독성이 훨씬 좋아지고 문제 진단에도 훨씬 유리하다.
- readLine 과 close 에서 모두 예외가 발생하면 먼저 발생한 readLine의 예외가 기록되고, close에서 발생한 예외는 숨겨지기 때문
- 이렇게 숨겨진 예외들은 스택 추적 내역에 숨겨졌다(suppressed)는 꼬리표를 달고 출력된다.
Throwable
의getSuppressed
메서드를 이용하면 프로그램 코드에서 가져올 수도 있다.
void addSuppressed(Throwwable exception) public final Throwable[] getSuppressed()
try-with-resources 와 함께 쓰이는 catch 구문
- try-with-resources와
catch
절을 함께 쓰면 try 문을 중첩하지 않고도 다수의 예외를 처리할 수 있다.
try { // 프로그램에서 사용하는 일반적인 코드를 입력 // 코드 실행 중 에러가 나면 그 자리에서 중단되고 catch문으로 이동 // 오류가 없다면 try 안의 구문을 모두 실행한다. } catch(Exception e) { // try에서 오류가 나면 catch안의 내용을 실행 // try에 오류가 없다면 catch는 실행되지 않는다. }
static String firstLineOfFile (String path, String defaultVal){ try (BufferedReader br = new BufferedReader(new FileReader(path))) { return br.readLine(); } catch (IOException e) { return defaultVal; } }
- 예외처리란, 프로그래머가 예기치못한 예외의 발생에 미리 대처하는 코드를 작성하는 것
- (나쁜)사용자가 발생시키는 예외에 대해, 개발자가 미리 대처를 해줄 수 있다.
- 실행중인 쓰레드의 비정상적인 종료를 막고 상태를 정상상태로 유지하는 것이 목적
- 예외가 처리되지 못한경우, 쓰레드은 비정상적으로 종료되며 처리되지 못한 예외의 원인을 JVM의 예외처리기(UncaughtExceptionHandler)가 화면에 출력해준다