[이펙티브 자바] 아이템 9: try-finally보다 try-with-resources를 사용하라
[이펙티브 자바] 아이템 9: try-finally보다 try-with-resources를 사용하라
자원 닫기, try-finally로 하다 보면
파일·소켓·DB 커넥션처럼 다 쓰면 close()를 호출해야 하는 자원이 많습니다. 전통적으로는 try-finally로 닫았는데, 자원이 둘 이상이면 코드가 금방 지저분해집니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ❌ 자원 두 개 → 중첩 try-finally
InputStream in = new FileInputStream(src);
try {
OutputStream out = new FileOutputStream(dst);
try {
byte[] buf = new byte[1024];
int n;
while ((n = in.read(buf)) >= 0) out.write(buf, 0, n);
} finally {
out.close();
}
} finally {
in.close();
}
더 큰 문제: 예외가 삼켜진다
try-finally엔 미묘한 함정이 있습니다. try 블록과 finally의 close()에서 둘 다 예외가 나면, 나중에 난 close() 예외가 앞의 진짜 원인을 덮어버립니다. 디버깅할 때 정작 중요한 첫 예외가 사라지는 거죠.
해결: try-with-resources
AutoCloseable을 구현한 자원이라면 try-with-resources로 훨씬 깔끔하게 쓸 수 있습니다.
1
2
3
4
5
6
7
8
// ✅ try-with-resources
try (InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[1024];
int n;
while ((n = in.read(buf)) >= 0) out.write(buf, 0, n);
}
// 블록을 벗어나면 선언의 '역순'으로 close()가 자동 호출됨
- 자원을
()안에 선언하면, 블록이 끝날 때 자동으로close()됩니다(여러 개면 역순). - 코드가 짧고 명확해집니다.
억제된 예외(Suppressed)
try-with-resources는 예외 문제도 해결합니다. try 본문과 close() 양쪽에서 예외가 나면, 본문의 예외가 주(primary) 가 되고 close()의 예외는 “억제됨(suppressed)” 으로 함께 보존됩니다. 스택 트레이스에 Suppressed:로 표시되어 둘 다 볼 수 있죠.
1
2
3
4
5
6
7
try {
// ...
} catch (IOException e) {
for (Throwable sup : e.getSuppressed()) {
// close()에서 발생해 억제된 예외들
}
}
catch 절도 함께 쓸 수 있어, 자원 정리와 예외 처리를 한 구조로 묶을 수 있습니다.
정리
- 자원 회수는
try-finally대신try-with-resources. - 코드가 짧고, 여러 자원도 깔끔하게(역순 자동 close).
- 억제된 예외 메커니즘으로 진짜 원인 예외가 사라지지 않는다.
- 전제: 자원이
AutoCloseable을 구현해야 한다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.
