[3] Try-with-Resources 와 AutoCloseable을 활용한 Java 리소스 관리
Java에서의 리소스 관리는 아주 중요한 요소이다. 과거에는 개발자가 파일, 소켓, 데이터베이스 연결과 같은 리소스를 명시적으로 닫아야 했고, 이는 종종 휴먼 에러(리소스 누수 등)를 초래했다. 실제로 며칠 전 내 업무관련 코드에서도 실수로 파일 관련 리소스를 닫지 않아 취약점 검사에 걸렸었다...😢 그래서 알아본게 바로 이것이다.
Try-with-Resources와 AutoCloseable 인터페이스 도입
위에 잠깐 말했듯이.. Java7 이전에는 개발자가 코드에서 파일, DB 등 리소스를 사용한 후에 finally 블록을 사용하여 리소스를 명시적으로 닫아야 했다. close 메서드를 호출하지 않으면 memory leak이 발생했고, 잘못 처리할 경우 오류가 발생했다. 다음은 명시적으로 리소스를 닫아주기 위한 보일러플레이트 코드다 (으.......;;;)
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("file.txt"));
// 파일에서 읽기
} catch (IOException e) {
// 예외 처리
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// 예외 처리
}
}
}
이후 Java 7에서 도입된 try-with-resources 구문과 AutoCloseable 인터페이스는 개발자가 리소스 관리를 편하게 할 수 있도록, 코드를 더욱 간결하게 만들 수 있도록 변화시켰다. 이 기능들은 리소스가 필요하지 않을 때 자동으로 리소스를 닫아줌으로써 명시적인 finally 블록을 없애 보일러플레이트 코드를 줄였다.
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
// 파일에서 읽기
} catch (IOException e) {
// 예외 처리
}
try 구문에서는 리소스를 초기화하며, 해당 블록이 종료될 때(예외가 발생하더라도) 리소스가 자동으로 닫히게 된다. 이 기능을 사용하기 위해서는 try 구문안에 초기화시키는 클래스에서 (예시에서는 BufferedReader) AutoCloseable 인터페이스 또는 그 하위 타입인 Closeable을 구현해야 한다. 거창한건 아니고 하나의 메서드 close()를 선언하며, 리소스가 더 이상 필요하지 않을 때 자동으로 호출하는 인터페이스다. 우리는 이 close 메서드에 리소스를 닫아주는 부분만 구현하면 되겠다.
public class MyResource implements AutoCloseable {
// 리소스 초기화 및 작업
@Override
public void close() throws Exception {
// 리소스 해제
}
}
Try-with-Resources의 장점
Try-with-Resources를 사용하며 얻는 장점은 다음과 같다.
- 간결성 및 가독성 : 보일러플레이트 코드 감소, 관리되고 있는 리소스 명확하게 확인 가능
- 자동 리소스 관리 : 메모리 누수 위험 감소
- 예외 처리 : 리소스 초기화 중 발생한 예외와 블록 실행 중 발생한 예외가 있을 경우, 블록 실행 중 발생한 예외가 우선 처리 -> 리소스 해제 중 발생한 예외는 suppressed exception으로 간주되며, getSuppressed() 메서드를 사용하여 확인 가능
- 다중 리소스 관리 : 하나의 try-with-resources 문에서 여러 개의 리소스 관리 가능