[Why]
- 자바 라이브러리에는 close 메서드를 호출해 직접 닫아줘야 하는 자원이 많다.
InputStream, OutputStream, java.sql.Connection 등 - 전통적으로 자원이 제대로 닫힘을 보장하는 수단으로 try-finally가 쓰였다.
// 자원이 둘 이상이면 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();
}
}
- 예외는 try 블록과 finally 블록 모두에서 발생할 수 있는데, 예컨대 기기에 물리적인 문제가 생긴다면 in.read(buf) 메서드가 예외를 던지고, 같은 이유로 close 메서드도 실패할 것이다.
- 이런 상황이라면 두 번째 예외가 첫 번째 예외를 완전히 집어삼켜, 첫 번째 예외에 대한 정보가 남지 않는다.
[When]
- 위의 문제들은 자바7에 등장한 try-with-resources 덕에 모두 해결되었다.
- 이 구조를 사용하려면 해당 자원이 AutoCloseable 인터페이스를 구현해야 한다.
- 닫아야 하는 자원을 뜻하는 클래스를 작성한다면 AutoCloseable을 반드시 구현하는 것이 좋다.
[How]
// 위의 예제를 try-with-resources를 사용해 재작성
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 블록과 finally 블록, 양쪽에서 예외가 발생하면 close에서 발생한 예외는 숨겨지고 try 쪽에서 발생한 예외가 기록된다.
- 숨겨진 예외들도 스택 추적 내역에 'suppressed' 꼬리표를 달고 출력된다.
- try-with-resources에서도 catch절을 쓸 수 있다. try문을 더 중첩하지 않고도 다수의 예외를 처리할 수 있다.
'독서찰기(讀書札記) > 이펙티브 자바' 카테고리의 다른 글
[아이템 11] equals를 재정의하려거든 hashCode도 재정의하라 (0) | 2022.01.08 |
---|---|
[아이템 10] equals는 일반 규약을 지켜 재정의하라 (0) | 2022.01.08 |
[아이템 8] finalizer와 cleaner 사용을 피하라 (0) | 2022.01.08 |
[아이템 7] 다 쓴 객체 참조를 해제하라 (0) | 2022.01.08 |
[아이템 6] 불필요한 객체 생성을 피하라 (0) | 2022.01.07 |