ㅇ.ㅇ
[Java] try-with-resources (자원 관리 최적화) 본문
반응형

자바에서 파일, 소켓, 데이터베이스 연결 같은 자원을 사용할 때는 반드시 사용 후에 반환해야 한다. 그렇지 않으면 메모리 누수나 시스템 리소스 낭비로 이어질 수 있다. 작년부터 파일 업로드, 다운로드 기능에 대한 리팩토링을 시간 날 때 조금씩 진행하고 있는데, 그 부분에서 try-with-resources 문법을 사용하였고 이번에 간단히 정리해보려고 한다.
1. try-with-resources란?
try-with-resources는 자원을 자동으로 닫아주는 기능을 제공하는 문법이다. (자바 7부터 제공)
try 블록에서 사용한 리소스를 finally 없이 자동으로 정리해준다.
기존 try-catch-finally 방식의 문제점 (리소스 수동 닫기)
- finally에서 close()를 수동으로 호출해야 함.
- close()에서도 예외가 발생할 가능성이 있어 다시 try-catch가 필요함.
- 코드가 복잡하고 가독성이 떨어짐.
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("test.txt"));
String line = br.readLine();
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close(); // 명시적으로 close() 호출
} catch (IOException e) {
e.printStackTrace();
}
}
}
try-with-resources 적용 (자동 리소스 정리)
- finally에서 close()를 호출할 필요 없음 → 코드가 간결해짐
- 예외가 발생하더라도 try 블록을 벗어나면 자동으로 자원 해제
- 여러 개의 리소스를 동시에 사용할 수도 있음
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
String line = br.readLine();
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
}
2. 여러 개의 리소스 사용하기
여러 개의 리소스를 try-with-resources에서 처리
- try 문 안에 여러 개의 리소스를 ;로 구분하여 선언 가능
- 모든 리소스가 자동으로 닫힘 (닫는 순서는 생성된 역순)
try (
FileInputStream fis = new FileInputStream("input.txt");
FileOutputStream fos = new FileOutputStream("output.txt")
) {
int data;
while ((data = fis.read()) != -1) {
fos.write(data);
}
} catch (IOException e) {
e.printStackTrace();
}
3. try-with-resources 동작 방식
try-with-resources가 어떻게 자동으로 close()를 호출하는지 확인해보자.
AutoCloseable 인터페이스
자바의 AutoCloseable 인터페이스를 구현하면 try-with-resources에서 사용할 수 있다.
class MyResource implements AutoCloseable {
@Override
public void close() {
System.out.println("리소스가 닫혔습니다.");
}
public void use() {
System.out.println("리소스를 사용 중...");
}
}
public class Main {
public static void main(String[] args) {
try (MyResource resource = new MyResource()) {
resource.use();
}
}
}
// 출력 결과
리소스를 사용 중...
리소스가 닫혔습니다.
- AutoCloseable 또는 Closeable을 구현하면 try-with-resources에서 자동으로 닫아줌.
- 자바의 여러 기본 클래스들은 이미 구현하고 있어서 try-with-resources 사용 가능~! (File, Buffered, Socket, Connection 등등) 개발자가 직접 close()를 호출할 필요 없음.
4. 예외 발생 시 처리 방식
try-with-resources의 예외 흐름
class MyResource implements AutoCloseable {
@Override
public void close() {
System.out.println("리소스 닫는 중...");
throw new RuntimeException("close()에서 예외 발생");
}
public void use() {
System.out.println("리소스 사용 중...");
throw new RuntimeException("use()에서 예외 발생");
}
}
public class Main {
public static void main(String[] args) {
try (MyResource resource = new MyResource()) {
resource.use();
} catch (Exception e) {
System.out.println("예외 발생: " + e.getMessage());
}
}
}
// 출력 결과
리소스 사용 중...
리소스 닫는 중...
예외 발생: use()에서 예외 발생
- try 블록에서 예외가 발생하면 close()가 실행된 후 catch로 전달됨.
- close()에서도 예외가 발생하면 Suppress된 예외로 관리됨.
숨겨진 예외 (Suppressed된 예외)
- 자바 7부터 try-with-resources는 close()에서 발생한 예외를 Suppress된 예외로 보관하여 원래 예외를 덮어버리지 않음.
- 자바의 try-catch-finally에서는 finally 블록에서 예외가 발생하면, try 블록에서 발생한 예외를 덮어버리는(무시하는) 문제가 있다. 즉, finally에서 발생한 예외가 마지막에 실행되므로, 원래 발생했던 예외 정보가 사라지는 것.
- 자바 7의 try-with-resources는 finally에서 발생한 예외를 덮어버리는 것이 아니라, Suppressed Exception으로 따로 보관한다. 즉, 원래 예외를 유지하면서 close()에서 발생한 예외도 함께 저장하는 방식이다.
- Suppressed Exception으로 저장하여 원래 예외를 유지하면서도 getSuppressed()로 확인할 수 있다. 추적이 가능하다는 것!
그럼 try-with-resources가 항상 최적의 선택일까?
- try-with-resources가 항상 최적의 선택일까? 대부분의 경우 코드 가독성과 안정성을 높여주지만, 특정한 상황에서는 기존 방식이 더 적절할 수 있다.
1) try-with-resources 사용하면 좋은 경우
- 자원 해제가 필수적인 경우 : 파일 입출력, 데이터베이스 연결, 네트워크 소켓처럼 사용 후 반드시 닫아야 하는 자원을 다룰 때는 try-with-resources가 매우 유용하다.
- 예외 처리가 간단한 경우 : 자원을 닫을 때 특별한 처리가 필요하지 않은 경우, try-with-resources를 사용하면 코드가 깔끔해진다.
- 여러 개의 자원을 사용할 때 : 다중 자원을 사용할 경우 try-with-resources가 특히 유용하다.
2) try-with-resources 적합하지 않은 경우
-
- 자원을 제어해야 하는 경우 : 어떤 자원은 특정 조건에서만 닫아야 할 수도 있다.
- 자원 해제 순서를 직접 제어해야 하는 경우 : try-with-resources는 생성된 역순으로 close()를 호출한다. 하지만 특정한 상황에서는 순서를 명확히 제어해야 할 수도 있다.
- 자원이 AutoCloseable을 구현하지 않은 경우 : try-with-resources는 AutoCloseable 인터페이스를 구현한 클래스에서만 동작한다. 만약 AutoCloseable을 구현하지 않은 클래스라면 기존 방식으로 처리해야 한다.
- close() 호출 시 예외가 발생해도 무조건 실행해야 하는 경우 : try-with-resources는 close()에서 예외가 발생하면 이를 Suppress된 예외로 관리한다. 하지만 어떤 경우든 close() 실행이 보장되어야 한다면 기존 방식이 더 안전할 수 있다
정리
- try-with-resources는 자원 관리를 자동화하는 기능으로, 코드 가독성을 높이고 예외 처리를 간결하게 해준다.
- AutoCloseable 또는 Closeable을 구현한 객체에서 사용할 수 있다.
- 여러 개의 리소스를 동시에 관리할 수 있으며, 생성된 역순으로 close()가 호출됨.
- 예외가 발생해도 자원이 자동으로 닫히며, close()의 예외는 Suppressed Exception으로 관리됨.
반응형
'Today I Learned' 카테고리의 다른 글
[Git] Stash (0) | 2025.03.23 |
---|---|
[Java] META-INF 디렉토리와 MANIFEST.MF (0) | 2025.03.12 |
[DEV] SBOM에 대하여 (0) | 2025.03.09 |
[Oracle] Oracle에서 NULL 값 다루기 (0) | 2025.03.09 |
[DEV] SSO (0) | 2025.03.02 |