[이펙티브 자바]try-finally보다는 try-with-resources를 사용하라_아이템9
InputStream, OutputStream, java.sql.Connection 등 close 메서드를 호출해 직접 닫아줘야하는 자원들이 많다.
[try-finally는 자원을 회수하는 최선의 방책이 아니다.]
static String firstLineOfFile(String path) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
br.close();
}
}
[자원이 둘 이상이면 try-finally 방식은 지저분하다.]
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();
}
}
물리적 문제가 생긴다면 firstLineOfFile 메서드 안의 readLine 메서드가 예외를 던지면, 같은 이유로 close 메서드도 실패할 것이다. => 두번째 예외가 첫번째 예외를 삼킨다.
[문제점] : 스택 추적 내역에 첫 번째 예외에 관한 정보는 남지 않아서 디버깅이 어렵다.
Finally 문제 해결 => try-with-resources 사용
try-with-resources 사용하기 위해 AutoCloseable인터페이스(void를 반환하는 close 메서드만 정의한 인터페이스)를 구현해야한다.
닫아야하는 자원의 클래스가 있다면 AutoCloseable을 반드시 구현하여 try-with-resources를 사용하자.
[try-with-resources 사용]
static String firstLineOfFile(String path) throws IOException {
try(BufferedReader br = new BufferedReader(
new FileReader(path))) {
return br.readLine();
}
}
[try-with-resources 복수 자원 처리]
static void copy(String src, String dst) throws IOException {
try (InputStream in = new FileInputStream(src);
OutputStream out = new FileInputStream(dst)) {
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf, 0, n);
}
}
firstLineOfFile 메서드에 readLine과 코드에 나타나지 않은 close 호출 양쪽에서 예외가 발생하면, close에서 발생한 예외는 숨겨지고 readLine에서 발생한 예외가 기록된다. 숨겨진 예외들은 버려지지않고 스택 추적 내역에 suppressed를 달고 출력된다. => Throwable에 추가된 getSuppressed메서드를 이용하면 프로그램 코드를 가져올 수 있다.
try-with-resources에서도 catch절을 쓸 수 있다. => try 문을 중첩하지 않고 다수 예외 처리 가능.
firstLineOfFile 메서드를 수정하여 파일을 열거나 데이터를 읽지 못할 때 예외 대신 기본 값을 반환하도록 해봤다.
[try-with-resources를 catch절과 함께 사용]
static String firstLineOfFile(String path, String defaultVal) {
try (BufferedReader br = new BufferedReader(
new FileReader(path))) {
return br.readLine();
} catch (IOException e) {
return defaultVal;
}
}
마무리로 회수할 자원을 다룰 땐 try-with-resources를 사용하자. 가장 정확하고 쉽게 자원을 회수할 수 있다.