yeonuel-tech
try-with-resources는 무엇이고 언제 써야할까? 본문
jdk 1.7부터 try-with-resources 문이 추가되었다. 이는 try-catch-finally 문에서 입출력(I/O) 관련 클래스를 사용할 때 발생하는 문제점 때문에 추가되었다. 일단, try-catch-fianlly 문에서 입출력(I/O) 관련 클래스를 사용할 때의 문제점부터 살펴보자.
1. 코드가 난잡해진다
try {
// 입출력(I/O) 클래스
fis = new FileInputStream("fileName.text");
dis = new DataInputStream(fis);
} catch (IOException e) {
e.printStackTrace();
} finally {
// 사용한 자원 반환하기
try {
if (dis != null) {
// close() 호출하여 사용한 자원 반환
dis.close();
}
// close() 메서드에서 IOException 발생할 수 있음
// 즉, try-catch 문으로 처리해야함
} catch (IOException e) {
e.printStackTrace();;
}
}
왜 이렇게 난잡해질까? 그 이유는 close()메서드에서는 IOException 예외가 발생할 수 있기 때문에
finally 문에서 또 다시 try-catch 문으로 예외 처리를 해줘야한다. 밑에는 close() 메서드의 선언부이다. 사진과 같이 throws로 IOException 예외를 던지는 것을 확인할 수 있다
하지만 이 보다 더 심각한 문제는 밑에 있다.
2. 에러 스택 트레이스가 누락된다
일단 밑에 코드를 간단하게 설명하면, MyResources 클래스에서는 2 가지 메서드를 지원하고 있고
둘 다 RuntimeException을 고의적으로 발생시켰다.즉, try 문에서 예외가 발생하고 finally 문에서 예외가 발생하고 있다.
class MyResources implements AutoCloseable {
@Override
public void close() throws RuntimeException {
System.out.println("call close()");
System.out.println();
throw new IllegalStateException("close()에서 런타임 예외 발생시킴"); // RuntimeException 발생
}
public void use() {
System.out.println("call use()");
throw new IllegalStateException("use()에서 런타임 예외 발생시킴"); // RuntimeException 발생
}
}
public class Main {
public static void main(String[] args) {
MyResources ms = null;
try {
ms = new MyResources();
ms.use(); // 고의적으로 RuntimeException 발생 1
} finally {
if (ms != null) {
ms.close(); // 고의적으로 RuntimeException 발생 2
}
}
}
}
콘솔에서 에러 스택 트레이스를 확인하면 try문의 예외가 무시된 것을 확인할 수 있다. 바로 try 블러과 finally 블럭에서 모두 예외가 발생하면 try 블럭의 예외가 무시된다는 것이다. 이는 에러 스택 트레이스가 누락되어 디버깅하기 어려워진다.
따라서 이러한 문제점을 보완하기 위해 try-with-resouces 문이 추가되었다. 이제는 try-with-resources 문을 적용하여 문제가 어떻게 해결되는지 확인해보자.
class MyResources implements AutoCloseable {
@Override
public void close() throws RuntimeException {
System.out.println("call close()");
System.out.println();
throw new IllegalStateException("close()에서 런타임 예외 발생시킴"); // RuntimeException 발생
}
public void use() {
System.out.println("call use()");
throw new IllegalStateException("use()에서 런타임 예외 발생시킴"); // RuntimeException 발생
}
}
public class Main {
public static void main(String[] args) {
try (MyResources ms = new MyResources()) {
ms.use();
} catch (Exception e) {
e.printStackTrace();
}
}
}
try-with-resources 문에서 객체를 자동 close() 해주려면 해당 객체는 AutoCloseable 인터페이스를 구현해야한다. AutoCloseable 인터페이스는 Closeable의 자식 인터페이스이므로 Closeable 인터페이스를 구현했으면 자동으로 close() 메서드를 호출할 수 있다. 이는 기존에 Closeable로 구현된 클래스도 변경 없이 try-with-resources 문을 사용하기 위함이다.
코드가 깔끔해지고 에러 스택 트레이스가 누락되지 않는 것을 확인할 수 있다. try-with-resources 문의 괄호안에 객체를 생성하면 이 객체는 자동으로 close()가 호출된다. 그리고 일반적인 예외와 close()에서 예외가 동시에 발생하면 일반적인 예외에 대한 내용이 출력되고 close()에서 발생한 예외는 '억제된(suppressed)'로 출력되는 것을 확인할 수 있다. 즉, 실제 발생한 예외를 보여주고 close()에서 발생한 예외는 억제된 예외로 다룬다.
결론적으로 try-with-resources는 try()문에 생성된 입출력(I/O) 클래스의 close() 메서드를 자동호출 해주고 예외를 적절히 처리해준다. 따라서, 입출력(I/O) 클래스를 사용할 때는 try-with-resources를 활용하여 깔끔한 코드 작성과 에러 스택 트레이스 누락 문제를 방지하자
- 참고
1. 망나니 개발자님 블로그
https://mangkyu.tistory.com/217
[Java] try-with-resources란? try-with-resources 사용법 예시와 try-with-resources를 사용해야 하는 이유
이번에는 오랜만에 자바 문법을 살펴보고자 합니다. Java7부터는 기존의 try-catch를 개선한 try-with-resources가 도입되었는데, 왜 try-catch가 아닌 try-with-resources를 사용해야 하는지, 어떻게 사용하는지
mangkyu.tistory.com
2. 자바의 정석(남궁성)
Java의 정석 | 남궁성 - 교보문고 (kyobobook.co.kr)
Java의 정석 | 남궁성 - 교보문고
Java의 정석 | 자바의 기초부터 실전활용까지 모두 담다!자바의 기초부터 객제지향개념을 넘어 실전활용까지 수록한『Java의 정석』. 저자의 오랜 실무경험과 강의한 내용으로 구성되어 자바를
product.kyobobook.co.kr
'programing-languages > Java' 카테고리의 다른 글
쓰레드를 구현하는 과정에서 쓰이는 패턴은? (작성중) (0) | 2024.03.27 |
---|---|
왜 인터페이스나 추상 클래스로 프로그래밍하는 것을 선호하는가? (0) | 2024.03.12 |
Integer 클래스에서 compare()메서드에 -를 안쓰고 < 부등호를 사용했을까? (0) | 2024.02.24 |
@SafeVarargs 애너테이션은 언제 사용하는 것일까?(이펙티브 자바 내용 넣기) (1) | 2024.02.24 |
Comparator와 Comparable 차이가 뭘까?(작성중) (0) | 2024.02.22 |