파일이나 네트워크 연결 같은 시스템 자원을 사용할 때, 이러한 자원들은 사용 후 반드시 적절하게 닫아주어야 한다.
그렇지 않으면 리소스 누수가 발생하여 시스템 성능 저하 또는 다른 문제를 일으킬 수 있다.
이 문제를 해결하기 위해 자바 7에서는 'Try-With-Resources' 구문이 도입되었다.
Try-With-Resources란?
Try-With-Resources는 자바 7부터 도입된 구문으로, try문을 사용하여 자원을 자동으로 관리할 수 있게 해준다.
이 구문은 AutoCloseable 인터페이스를 구현한 모든 객체에 대해 작동하며, 이러한 객체들은 try문이 종료될 때 자동으로 close() 메서드가 호출되어 자원이 안전하게 닫히게 된다.
Try-With-Resources 사용 예제
try (FileInputStream fis = new FileInputStream("example.txt")) {
// 파일에서 데이터 읽기
int data = fis.read();
while(data != -1) {
System.out.print((char) data);
data = fis.read();
}
} catch (IOException e) {
e.printStackTrace();
}
FileInputStream은 AutoCloseable 인터페이스를 구현한다.
따라서 try문이 종료될 때 자동으로 close() 메서드가 호출되어 파일이 안전하게 닫힌다.
Try-With-Resources를 사용하지 않았을 때 예제
FileInputStream fis = null;
try {
fis = new FileInputStream("example.txt");
// 파일에서 데이터 읽기
int data = fis.read();
while(data != -1) {
System.out.print((char) data);
data = fis.read();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Try-With-Resources를 사용하지 않았을 때의 코드다.
여기서는 finally 블록을 명시적으로 사용하여 close() 메서드를 호출해야 한다.
이 과정은 번거롭고 오류를 일으킬 여지가 많으며, 자원을 닫는 코드를 잊어버릴 수도 있다.
여러 자원 사용하기
자바의 Try-With-Resources 구문은 여러 자원을 동시에 관리할 수 있도록 설계되어 있다.
이는 각 자원을 세미콜론(;)으로 구분하여 try() 괄호 안에 선언함으로써 가능하다. 이렇게 하면 모든 자원이 사용된 후 자동으로 닫히게 되므로, 자원 해제와 관련된 코드를 간소화할 수 있다.
여러 자원 사용 예제
try (FileInputStream fis = new FileInputStream("example1.txt");
FileOutputStream fos = new FileOutputStream("example2.txt")) {
// example1.txt에서 데이터를 읽고 example2.txt에 데이터를 쓴다.
int data;
while ((data = fis.read()) != -1) {
fos.write(data);
}
// 자원 사용
} catch (IOException e) {
e.printStackTrace();
}
위 예제에서는 두 개의 자원, FileInputStream과 FileOutputStream,을 사용하고 있다. Try-With-Resources 구문 덕분에 이 두 자원은 모두 자동으로 안전하게 닫힌다.
자원 닫히는 순서
여러 자원을 Try-With-Resources 구문에서 사용할 경우, 자원은 역순으로 닫히게 된다. 즉, 마지막으로 선언된 자원이 먼저 닫히고, 처음 선언된 자원이 가장 마지막에 닫힌다. 이러한 동작 방식은 스택의 후입선출(LIFO) 원칙과 유사하다. 이는 서로 연관된 자원들이 의존성의 순서에 맞게 올바르게 닫힐 수 있도록 설계된 것이다.
자원 닫히는 순서 예제
try (FileInputStream fis = new FileInputStream("example1.txt");
FileOutputStream fos = new FileOutputStream("example2.txt")) {
// 여기서는 fis가 먼저 열리고, 그 다음 fos가 열린다.
// 따라서 닫힐 때는 fos가 먼저 닫히고, 그 다음 fis가 닫힌다.
} catch (IOException e) {
e.printStackTrace();
}
FileOutputStream(fos)이 FileInputStream(fis) 다음에 선언되었다.
따라서 fos는 fis보다 먼저 닫힌다.
이 순서는 중요한데, 왜냐하면 어떤 경우에는 한 자원이 다른 자원에 의존적일 수 있기 때문이다.
예를 들어, 먼저 읽은 데이터를 쓰는 경우, 쓰기 작업을 수행하는 자원을 먼저 닫아서 모든 쓰기 작업이 완료되었음을 보장해야 한다.
Try-With-Resources를 통해 자원을 자동으로 관리해주므로 개발자가 직접 close() 메서드를 호출하는 번거로움을 줄여준다.
특히, 파일 입출력, 데이터베이스 연결, 네트워크 세션 관리 등 다양한 자원을 사용하는 상황에서 그 진가가 발휘된다.
코드의 가독성을 높이고, 자원 누수의 가능성을 줄일 수 있다.
파일, 네트워크 연결 등 AutoCloseable 인터페이스를 구현한 자원을 다룰 때는 Try-With-Resources 구문을 활용하는 것이 좋다.
'IT > Java' 카테고리의 다른 글
성능 저하 및 Full GC - e.printStackTrace()를 피해야 하는 이유 (0) | 2024.02.28 |
---|---|
스프링 부트: 윈도우와 맥에서 한글 파일명 다운로드 문제 해결하기(2) (0) | 2024.01.25 |
Effective Java: 생성자에 많은 매개변수가 필요할 때: 빌더 패턴 고려하기 (0) | 2024.01.24 |
Spring에서 CORS 설정하기 (0) | 2024.01.23 |
Effective java: 생성자 대신 정적 팩터리 메서드 요약 (0) | 2024.01.23 |