1. try-with-resources란?
try-with-resources
는 자원을 자동으로 관리하기 위한 구문으로, 자원을 명시적으로 닫지 않아도 자동으로 해제됩니다. 파일, 네트워크 소켓, 데이터베이스 연결과 같은 자원들은 반드시 사용 후 닫혀야 합니다. 자바 7에서 도입된 try-with-resources
는 이러한 자원을 자동으로 해제하는 구조를 제공합니다.
1.1 자원(Resource)이란?
자바에서 자원이란 사용 후 반드시 해제해야 하는 외부 시스템과의 연결을 의미합니다. 파일, 데이터베이스 연결, 네트워크 소켓 등이 자원에 해당합니다. 자원을 닫지 않으면 메모리 누수나 시스템 리소스 고갈 문제가 발생할 수 있습니다.
1) 자원의 종류
- 파일: 파일을 읽고 쓰기 위한
FileReader
,BufferedReader
등 - 데이터베이스 연결:
Connection
,Statement
등의 데이터베이스 관련 자원 - 네트워크 소켓: 네트워크 통신을 위한
Socket
객체
자원은 사용 후에 반드시 닫아야 하며, 닫지 않으면 리소스 누수로 이어져 시스템 성능에 영향을 미칠 수 있습니다.
1.2 try-with-resources의 기본 규칙
try-with-resources
구문에 사용되는 자원은 반드시AutoCloseable
또는Closeable
인터페이스를 구현해야 합니다.try
블록이 끝나면 자동으로close()
메서드가 호출되어 자원을 해제합니다.- 한 번 선언된 자원은
try
구문이 끝날 때 자동으로 닫히기 때문에 수동으로 자원을 해제하는 과정에서 발생할 수 있는 오류를 방지할 수 있습니다.
2. try-catch-finallly와 try-with-resources 구문 비교
2.1 기존 자원 관리 방식 (try-catch-finally)
자바 7 이전에는 자원을 해제하려면 try-catch-finally
구문에서 자원을 수동으로 닫아야 했습니다. 자원을 해제하지 않으면 메모리 누수나 시스템 오류가 발생할 수 있기 때문에, finally
블록에서 반드시 close()
메서드를 호출해야 했습니다.
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(); // 자원을 반드시 닫아야 함
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
- 자원을 닫는 것을 잊을 수 있음:
finally
블록에서 자원을 닫지 않으면 리소스 누수가 발생할 수 있습니다. - 코드 복잡도: 자원이 여러 개일 경우, 각각의 자원에 대해
null
확인 및close()
호출을 반복해야 합니다. - 중첩된 예외 처리의 어려움: 자원 해제 중 발생한 예외와 원래 발생한 예외를 동시에 처리하기 어렵습니다.
2.2 try-with-resources 구조
자바 7부터 도입된 try-with-resources
는 자원을 자동으로 닫아주는 구조입니다. try
구문 안에서 자원을 생성하면, try
블록이 끝나면 자동으로 자원을 닫습니다. 이 덕분에 finally
블록에서 자원을 닫는 작업을 수동으로 할 필요가 없습니다.
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
// 파일을 읽는 로직
String line = br.readLine();
System.out.println(line);
} catch (IOException e) {
// 예외 처리
e.printStackTrace();
}
- 자원의 자동 해제:
try
블록이 끝나면 자원이 자동으로 닫힙니다. - 코드 간결성:
finally
블록에서 수동으로 자원을 닫을 필요가 없어 코드가 간결해집니다. - 안정성: 자원 해제 중 발생하는 예외를 억제된 예외로 처리할 수 있습니다.
3. Closeable과 AutoCloseable의 관계
try-with-resources
에서 사용할 수 있는 자원은 반드시 AutoCloseable
또는 Closeable
인터페이스를 구현해야 합니다. 두 인터페이스 모두 자원을 닫을 수 있는 메서드를 제공하지만, AutoCloseable
은 자바 7에서 추가되었고, Closeable
은 자바 5부터 존재합니다.
3.1 AutoCloseable 인터페이스
AutoCloseable
은 자바 7에서 도입된 인터페이스로, 자원을 닫기 위한close()
메서드를 정의합니다.AutoCloseable
을 구현한 객체는try-with-resources
구문에서 사용할 수 있습니다.
public interface AutoCloseable {
void close() throws Exception;
}
3.2 Closeable 인터페이스
Closeable
은 자바 5에서 도입된 인터페이스로, I/O 자원을 닫기 위한close()
메서드를 정의합니다.- 자바 7에서
AutoCloseable
이 새롭게 등장한 후, 기존의Closeable
인터페이스에AutoCloseable
을 상속받는 구조가 추가되었습니다.변경된 이유는try-with-resources
구문을 사용하면서 기존에 있던Closeable
을 포함하여 모든 자원을 자동으로 닫을 수 있도록 하기 위해서입니다.
public interface Closeable extends AutoCloseable {
void close() throws IOException;
}
3.3 차이점
AutoCloseable
은 모든 자원에 적용 가능한 범용적인 인터페이스로Exception
을 던질 수 있습니다.Closeable
은 I/O 작업에 특화된 인터페이스로,IOException
만 던질 수 있습니다. 주로 파일 입출력에 사용됩니다.
4. try-with-resources를 사용해야 하는 이유
4.1 자원 해제의 안정성
try-with-resources
를 사용하면 자원을 안전하게 해제할 수 있습니다. 자원 해제 코드를 수동으로 작성할 때 발생할 수 있는 실수를 줄일 수 있으며, 예외가 발생하더라도 자원이 자동으로 해제됩니다.
1) 중첩된 예외 처리
자원 해제 시 발생한 예외와 원래의 예외를 모두 처리할 수 있습니다. 기존 finally
블록에서는 자원을 닫는 과정에서 새로운 예외가 발생하면 원래 예외가 가려지는 문제가 있었습니다.
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
String line = br.readLine(); // 예외 발생 가능
System.out.println(line);
} catch (IOException e) {
// 예외 처리
e.printStackTrace();
} // 자원이 자동으로 해제됨
4.2 코드의 간결성
try-with-resources
를 사용하면 자원을 닫는 finally
블록을 작성할 필요가 없으므로 코드가 간결해지고 가독성이 높아집니다. 여러 자원을 사용할 때도 하나의 try
구문에서 관리할 수 있습니다.
1) 여러 자원을 사용하는 경우
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"));
FileWriter fw = new FileWriter("output.txt")) {
String line = br.readLine();
fw.write(line);
} catch (IOException e) {
e.printStackTrace();
}
// 두 자원 모두 자동으로 해제됨
5. 예시를 통해 알아보기
5.1 try-catch-finally
를 사용할 경우 (자원 해제 중 예외가 발생할 때)
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class TryCatchFinallyExample {
public static void main(String[] args) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("test.txt"));
String line = br.readLine(); // 예외 발생 가능
System.out.println(line);
} catch (IOException e) {
// 파일 읽기 중 발생한 예외 처리
System.out.println("파일을 읽는 도중 오류 발생");
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close(); // 자원을 닫는 과정에서 예외 발생 가능
} catch (IOException e) {
// 자원 해제 중 발생한 예외 처리
System.out.println("자원을 닫는 도중 오류 발생");
e.printStackTrace();
}
}
}
}
}
- 파일 읽기 중 예외가 발생할 경우,
catch
블록에서 해당 예외를 처리합니다. - 자원을 닫는 과정에서 예외가 발생할 수 있습니다. 이때
finally
블록에서br.close()
를 호출하여 자원을 닫으려고 하지만, 닫는 도중에 예외가 발생할 수 있습니다. 이렇게 되면 자원을 닫는 중 발생한 예외는 별도로 처리됩니다. - 문제점: 파일을 읽는 중 발생한 원래 예외와 자원을 닫는 중 발생한 예외가 서로 독립적으로 처리되기 때문에, 원래 예외는 가려질 수 있습니다.
5.2 try-with-resources
를 사용할 경우 (자원 해제 중 예외가 발생할 때)
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class TryWithResourcesExample {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
String line = br.readLine(); // 예외 발생 가능
System.out.println(line);
} catch (IOException e) {
// 파일 읽기 중 발생한 예외와 자원 해제 중 발생한 예외를 함께 처리
System.out.println("파일 읽기 또는 자원 해제 중 오류 발생");
e.printStackTrace();
}
}
}
try-with-resources
에서는 자원이 자동으로 해제되므로,finally
블록을 수동으로 작성할 필요가 없습니다.- 중첩된 예외 처리:
- 파일을 읽는 중 예외가 발생해도, 자원이 자동으로 닫힙니다.
- 자원을 닫는 도중에 예외가 발생해도 원래 발생한 예외와 자원 해제 중 발생한 예외를 함께 처리할 수 있습니다.
- 자바는
try-with-resources
에서 첫 번째 예외를 그대로 남겨두고, 자원 해제 중 발생한 예외는suppressed exception
으로 관리합니다.
5.3 중첩된 예외 확인하기 (getSuppressed()
사용)
try-with-resources
는 자원을 닫는 중 발생한 예외를 억제된 예외(suppressed exception)로 저장합니다. 이를 확인하는 예시입니다.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class TryWithResourcesSuppressedExample {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("non_existent_file.txt"))) {
String line = br.readLine(); // 예외 발생 가능
} catch (IOException e) {
System.out.println("메인 예외: " + e.getMessage());
// 억제된 예외 확인
for (Throwable suppressed : e.getSuppressed()) {
System.out.println("억제된 예외: " + suppressed.getMessage());
}
}
}
}
getSuppressed()
메서드를 사용하면 자원을 닫는 중 발생한 억제된 예외들을 확인할 수 있습니다.try-with-resources
를 사용하면 자원 해제 중 발생한 예외가 메인 예외에 억제된 형태로 추가되어, 두 예외를 모두 처리할 수 있습니다.
6. 결론
try-with-resources
는 자바 7에서 도입된 자원 관리 기능으로, 자원을 자동으로 닫아줍니다. 이로 인해, 자바에서 메모리 누수나 리소스 낭비 문제를 방지할 수 있습니다.- 자바 7 이전의
try-catch-finally
구문에서 자원을 수동으로 닫는 문제를 해결합니다. - I/O 자원 관리에서 매우 유용하며, 코드의 간결성과 가독성을 크게 향상시킵니다.
AutoCloseable
또는Closeable
인터페이스를 구현한 객체만 사용할 수 있지만, 이를 통해 코드가 간결해지고 예외 처리의 안전성이 보장됩니다.
'BackEnd > JAVA' 카테고리의 다른 글
[JAVA] 스레드 (Thread) 정리 (2) | 2025.01.25 |
---|---|
[JAVA] 인터페이스 심화: 다중 상속, 다중 구현 (3) | 2025.01.20 |
[JAVA] 자바 부모클래스 및 인터페이스 심화: 오버라이딩과 메서드 동작 (0) | 2025.01.17 |
[JAVA] 인터페이스 정리 (0) | 2025.01.12 |
[JAVA] 추상 클래스 (Abstract Class) 정리 (0) | 2025.01.09 |