아이템 9. try finally 보다는 try with resources를 사용하라. - ksw6169/effective-java GitHub Wiki
개요
- 자바 라이브러리에는
close()
를 호출해 직접 닫아줘야 하는 자원이 많다. (InputStream
,Connection
등) - 자원 닫기는 클라이언트가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어지기도 한다.
- 이러한 자원 중 상당수가 안전망으로
finalizer
를 활용하고는 있지만finalizer
는 그리 믿을만하지 못하다. - 전통적으로는 자원이 제대로 닫히도록 보장하는 수단으로
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()
양쪽에서 예외가 발생하면close()
에서 발생한 두 번째 예외가 첫 번째 예외를 완전히 집어삼켜 버린다. 그러면 스택 추적 내역에 첫 번째 예외에 관한 정보는 남지 않게 되어 실제 시스템에서의 디버깅을 몹시 어렵게 한다. (실제 디버깅할 때 중요한 예외는 첫 번째 예외이므로) - 이러한 문제들은 Java 7에 도입된
try-with-resources
구문으로 모두 해결되었다.
AutoCloseable
try-with-resources
구조를 사용하려면 해당 자원이AutoCloseable
인터페이스를 구현해야 한다.- 자바, 서드파티 라이브러리들의 수많은 클래스와 인터페이스가 이미
AutoCloseable
을 구현하거나 확장해뒀다. - 닫아야 하는 자원 클래스에는 반드시
AutoCloseable
을 구현하라.
public interface AutoCloseable {
void close() throws Exception;
}
try-with-resources
- 아래는
try-with-resources
구문을 사용한 예제다.
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 (InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[BUFFER_SIZE;
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf, 0, n);
}
}
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의 장점
-
가독성이 좋고 문제를 진단하기도 훨씬 좋다.
-
중요한 예외 하나만 보존되고 여러 개의 다른 예외가 숨겨질 수 있다.
- 앞의 예제
firstLineOfFile()
에서readLine()
과close()
양쪽에서 예외가 발생하면close()
에서 발생한 예외는 숨겨지고readLine()
에서 발생한 예외가 기록된다. 여기서 숨겨진 예외들은 버려지지 않고 스택 추적 내역에 '숨겨졌다(suppressed)' 는 꼬리표를 달고 출력된다. 이는 Java 7의Throwable
에 추가된getSuppressed()
를 이용하면 코드에서 가져올 수도 있다.
- 앞의 예제
참고 자료
- Effective Java 3/E