try with resources 문법은 try-catch문에서 선언된 객체들에 대해 try문을 벗어날 때 자동으로 자원을 해제해주는 문법이다.
사실 여기서 글 작성을 완료해도 되지만..예시를 들어야겠죵?
기존에는 다음과 같이 자원을 해제했었다.
try {
is = new FileInputStream("file.txt");
dis = new DataInputStream(is);
// ...생략
} catch (IOException e) {
e.printStackTrace();
} finally {
dis.close();
}
DataInputStream을 이용해 파일로부터 데이터를 읽는 코드로, 데이터를 읽다가 예외가 생겨도 finally블록의 close를 통해 자원을 해제한다. 그러나 사실 close()가 예외를 발생시킬 수 있다는 함정이 숨어 있다. 따라서 finally블록 안에서 다시 한 번 try catch를 해줘야 한다.
try {
is = new FileInputStream("file.txt");
dis = new DataInputStream(is);
// ...생략
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dis != null) {
dis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
그러나 indent가 꽤나 늘어나게 되는 걸 볼 수 있다. 한 눈에 봐도 코드가 더러워진다..좀 더 쉽게 자원을 해제하고 싶은 우리를 위한 바로 그 문법! try-with-resources문법이다. try의 괄호 () 안에 객체를 생성하는 코드를 넣으면, 그 객체는 따로 close()를 호출하지 않아도 try블록을 벗어나는 순간 자동적으로 close()를 호출하게 된다.
try (is = new FileInputStream("file.txt");
dis = new DataInputStream(is)) {
// ...생략
} catch (IOException e) {
e.printStackTrace();
}
그렇다고 아무 객체나 냅다 반납(해제)가 가능한 건 아니다. try-with-resources문법으로 해제되고 싶은(?) 객체는 AutoCloseable이라는 인터페이스를 구현을 해야한다. 다음 코드가 AutoCloseable인터페이스다.
public interface AutoCloseable {
void close() throws Exception;
}
코드의 복잡도를 줄여준다는 점 외에도 자원 해제를 해야 하는 경우 try-with-resources문법을 사용하는 게 좋은 이유는 또 하나 있다. 그건 바로 에러 스택 트레이스가 누락될 수 있다는 점이다. 다음과 같은 클래스가 있다고 해보자.
public class CloseableResource implements AutoCloseable {
public void exceptionWork() throws WorkException {
System.out.println("exceptionWork()가 호출됨!");
throw new WorkException("WorkException 발생!!");
}
public void close() throws CloseException {
System.out.println("close()가 호출됨!");
throw new CloseException("CloseException 발생!!");
}
}
class WorkException extends Exception {
WorkException(String message) {
super(message);
}
}
class CloseException extends Exception {
CloseException(String message) {
super(message);
}
}
그리고 다음과 같은 try-catch-finally문이 있다고 하자.
CloseableResource cr = null;
try {
cr = new CloseableResource();
cr.exceptionWork();
} finally {
if (cr != null) {
cr.close();
}
}
우선 try블록에서 WorkException를 발생시킨다. 그리고 예외의 발생여부에 상관없이 항상 실행되는 finally 블록에서 close를 해주는데, 이 때 CloseException도 발생될 것이다. 그러면 우리의 상식(?)으로는 에러 스택 트레이스에 Work, CloseException이 둘 다 쌓여야 한다. 그러나 결과는..
보다시피 try블록에서 발생했던 WorkException이 누락된 모습이다. 비단 try블록 뿐만이 아닌 catch블록에서 발생된 예외도 이와 같은 상황에선 누락된다. 이러한 문제가 실무에서 발생됐다면.. 그 원인을 파악하기가 좀처럼 쉽지만은 않을 것이다.
그러나 다음과 같이 try-with-resources문으로 작성했다면 어떨까.
try (CloseableResource cr = new CloseableResource()) {
cr.exceptionWork();
}
WorkException이 일어나고 try블록을 벗어나면서 close()가 호출되며 CloseException도 일어날 것이다. 결과는..
에러 트레이스가 누락되지 않은 모습을 볼 수 있다!! 때문에, 자원을 해제하는 경우 try-with-resources문법을 쓰는게 좋을 것이다.
'WEB > JAVA' 카테고리의 다른 글
JDK21부터 도입된 자바의 마법, Virtual Thread (4) | 2024.10.09 |
---|---|
JNI(Java Native Interface)란? (feat. 자바 스레드 생성) (1) | 2024.09.15 |
이 함수형 인터페이스에는 추상메서드가 2개 이상인데요? (feat.Object) (0) | 2024.07.21 |
Optional 뜯어보기 (0) | 2023.01.13 |