언어/Effective Java
이펙티브 자바 Item 9 - try-finally 대신 try-with-resources를 사용하라
now0204
2024. 5. 28. 12:04
자바 라이브러리에는 close 메서드를 호출해 직접 닫아줘야 하는 자원이 많다.
ex)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-with-resources
이 구조를 사용하려면, 해당 자원이 AutoCloseable인터페이스를 구현해야한다.
이 메서드는 단순히 close 메서드 하나만 정의한 인터페이스이다. 닫아야 하는 자원을 뜻하는 클래스를 작성한다면 해당 인터페이스를 구현해야 한다.
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);
}
}
- 간결하게 선언 및 사용이 가능하다.
* AutoCLoseable 구현
public class MyResource implements AutoCloseable {
public void doSomething() throws FirstError {
System.out.println("doing something");
throw new FirstError();
}
@Override
public void close() throws SecondException {
System.out.println("clean my resource");
throw new SecondError();
}
}
public class MyResource implements AutoCloseable {
public void doSomething() throws FirstError {
System.out.println("doing something");
throw new FirstError();
}
@Override
public void close() throws SecondException {
System.out.println("clean my resource");
throw new SecondError();
}
}
public class AppRunner {
public static void main(String[] args) {
MyResource myResource = new MyResource();
try {
myResource.doSomething();
} finally {
myResource.close();
}
}
}
- 이와 같이 작성하면, try블럭과 finally 블록에서 모두 예외가 발생할 수 있는데
- finally 예외가 try의 예외를 집어삼켜 버린다.
- 스택 추적에서 첫 번째 예외에 관한 정보가 남지 않게 되어, 실제 시스템에서 디버깅이 어렵다.
public class AppRunner {
public static void main(String[] args) {
try (MyResource myResource = new MyResource()){
myResource.doSomething();
}
}
}
- try-with-resources문을 사용하면, close의 예외가 숨겨지고 첫 번쨰 예외가 기록된다.
- 실전에서는 예외 하나만 보존되고 여러 개의 예외가 숨겨질 수 있다.
- 이렇게 숨겨진 예외들은 스택 추적 내역에 suppressed 꼬리표를 달고 출력된다.
- 자바7에서 Throwable에 추가된 getSuppressed 메서드를 쓰면 프로그램 코드에서 가져올 수 있수도 있다.!
참고자료
https://marxsoftware.blogspot.com/2012/04/java-7s-support-for-suppressed.html