자바 라이브러리에는 InputStream, OutputStream, java.sql.Connection 등 close() 메서드를 이용해 닫아야 하는 자원이 많다. 그러나 자원 닫기는 예측할 수 없는 예외가 발생하면 클라이언트가 놓치기 쉽다. 이런 자원 중 대부분이 finalizer를 사용하지만 믿을만하지 못하다.
자원을 닫기 위해 try-finally를 사용하는 경우
아래 코드에서는 자원이 제대로 닫히는 것을 보장하는 수단으로 항상 실행됨을 보장하는 try-finally를 사용했다. 그러나 예외는 try문과 finally 문에서 모두 발생할 수 있다.
만약 기기에 물리적인 문제가 생긴다면 readLine 메서드에 문제가 생겨 예외를 던지고 close()도 실패할 것이다. 이 경우 스택 추적 내역은 두 번째 예외만을 기록할 것이고 디버깅을 어렵게 한다.
// 자원을 한 개 사용하는 경우
static String firstLineOfFile(String path) throws IOException {
BufferReader bt = new BufferReader(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 FileOutputStrieam(dst);
try {
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf, 0, n);
} finally {
cout.close();
}
}
}
자원을 닫기 위해 try-with-resources를 사용하는 경우
자바 7은 리소스를 닫아야만 하는 자원은 AutoCloseable 인터페이스를 사용하게끔 했다. 아래 코드처럼 AutoClosable을 구현한 리소스에 try-with-resources를 사용하면 길이가 짧아져서 읽기 수월할 뿐 아니라 문제를 진단하기도 훨씬 쉽다.
이전 상황과 달리, 만약 close() 호출 양쪽에서 예외가 발생하면, close()에서 발생한 예외는 숨겨지고 readLine에서 발생한 예외만 기록된다.
try-finally에서처럼 try-with-resources에도 catch 절을 쓸 수 있으므로 try문을 중첩하지 않고도 다수의 예외를 처리할 수 있다.
static String firstLineOfFile(String path) throws IOException {
try (BufferReader 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);
}
}
'Java > 내맘대로 Effective Java' 카테고리의 다른 글
[Item 11] equals를 재정의하려거든 hashCode도 재정의해라 (0) | 2022.03.15 |
---|---|
[Item 10] equals는 일반 규약을 지켜 재정의하라 (0) | 2022.03.11 |
[Item 8] finalizer와 cleaner 사용을 피하라 (0) | 2022.03.10 |
[Item 7] 다 쓴 객체 참조를 해제하라 (0) | 2022.03.08 |
[Item 6] 불필요한 객체 생성을 피하라 (0) | 2022.03.06 |