자바에서 스트림이나 커넥션같은 자원은 다 사용한 후에 close 구문을 따로 작성해야하는 불편이 있었습니다. Try-with-resource 구문을 사용하게 되면 자원을 자동으로 반납할 수 있습니다.
Try-with-resource을 사용해야하는 이유와 리소스 개수에 따른 동작순서 소개
자바 InputStream이나 JDBC를 커넥션등은 다 사용하고나면 자원을 반드시 close 해주어야하는데요. 코드에서 직접 close문을 작성하지 않더라도, 자동으로 자원을 반납할 수 있는 예외처리 메커니즘이 있습니다. 바로 Try-with-resource 구문인데요. 아래 본문에서 소개드리겠습니다.
1. Try-with-resources 기본 문법 소개 및 예시
private static void printFile() throws IOException {
try(FileInputStream input = new FileInputStream("file.txt")) {
int data = input.read();
while(data != -1){
System.out.print((char) data);
data = input.read();
}
}
}
printFile이라는 메서드가 있습니다. file.txt에서 내용을 읽어오기 위해 FileInputStream을 가져와 읽어들이는 코드입니다.
try(FileInputStream input = new FileInputStream("file.txt")) { ... }
try 구문 뒤에는 이렇게 괄호가 있습니다. 블럭 안에서 사용하고자 하는 자원을 괄호 안에서 선언을 해줍니다. 이렇게 작성해주면 블럭 안의 코드가 모두 수행되고 난 후에 사용이 끝난 FileInputStream을 자동으로 닫아줍니다(close).
FileInputStream input = new FileInputStream("file.txt");
try(input) { ... }
그리고 자바 9부터는 try 블럭 바깥에 선언한 자원을 괄호 안에 참조변수로 사용할 수 있습니다.
2. Try-with-Resources에서 여러개의 자원 선언해서 사용하기
private static void printFile() throws IOException {
try( FileInputStream input = new FileInputStream("file.txt");
BufferedInputStream bufferedInput = new BufferedInputStream(input);
) {
int data = bufferedInput.read();
while(data != -1){
System.out.print((char) data);
data = bufferedInput.read();
}
}
}
이번에는 try문의 괄호 안을 보면 FileInputStream과 BufferedInputStream 두 개의 자원이 선언되어 있는 것을 볼 수 있습니다. 블럭 안에서 여러개의 자원을 사용하고 싶을땐 이렇게 선언을 하면 됩니다.
여러개의 자원이 선언된 경우, 자원을 닫는 순서
FileInputStream input = new FileInputStream("file.txt");
BufferedInputStream bufferedInput = new BufferedInputStream(input);
괄호안에 자원을 선언했기 때문에 이제 자동으로 close될 것은 예상할 수 있는데요. 자원이 닫히는 순서는 어떻게 될까요? 자원이 닫힌 순서는 나중에 선언된 것 부터 종료됩니다. 위 코드에서는 BufferedInputStream이 close되고, 그다음 FileInputStream이 close됩니다.
3. 내가 만든 클래스에서도 Try-with-resources 구문 사용하기
그럼 개발자가 직접 생성한 클래스의 인스턴스들도 try 구문 안에만 넣으면 자동으로 자원을 close 해주는지 의문이 생기는데요. 직접 만든 클래스도 Try-with-resources 구문에서 자동으로 자원을 close 시키려면 AutoCloseable 인터페이스만 상속받으면 가능합니다.
위 예시 코드에서 소개드렸던 FileInputStream과 BufferedInputStream 자바9 공식문서를 확인해보면 둘 다 AutoCloseable이라고 하는 인터페이스를 상속받아 구현하고 있는 것을 확인할 수 있습니다.
public interface AutoClosable {
public void close() throws Exception;
}
AutoClosable 인터페이스는 위와 같이 close 추상 메서드를 1개 가지고 있는 단순한 인터페이스입니다.
public class MyAutoClosable implements AutoCloseable {
public void doIt() {
System.out.println("MyAutoClosable doing it!");
}
@Override
public void close() throws Exception {
System.out.println("MyAutoClosable closed!");
}
}
직접 선언한 클래스에서 이렇게 AutoClosable을 상속하여 close 메서드를 오버라이딩합니다. 그러면 위 코드에서 MyAutoClosable 클래스의 인스턴스는 이제 try-with-resources 구문에 넣으면 자동으로 close가 가능한 상태가 됩니다.
try(MyAutoClosable myAutoClosable = new MyAutoClosable()){
myAutoClosable.doIt();
}
// MyAutoClosable doing it!
// MyAutoClosable closed!
방금 만든 MyAutoClosable클래스의 인스턴스를 생성해서 doIt 메서드를 호출해보면 위와 같은 순서로 메시지가 출력 됩니다.
참고) Try-catch-finally(기존 방식) 구문과 비교
Try-with-resources과 Try-catch-finally 구문을 비교해보겠습니다. 먼저 Try-catch-finally는 기존부터 자바 예외처리에서 사용하던 구문이고, Try-with-resources는 자바 7버전부터 지원하고 있습니다.
두 구문의 블럭 안에서 Exception이 발생(throw)하게 되면 try 구문을 빠져나가며 상위 호출 스택으로 전파됩니다. Try-with-resources 구문은 괄호안에 선언한 자동으로 리소스를 먼저 닫아주고 Exception이 전파된다는 차이가 있습니다.
'기술 블로그' 카테고리의 다른 글
자바 Heapdump 생성하는 방법, MAT 이용해 메모리릭 분석하기 (0) | 2023.03.24 |
---|---|
webSocket 정상연결 후 Pending 원인분석, 웹소켓 정상동작 테스트하는 방법 소개 (0) | 2023.02.28 |
[Spring] @Transactional 동작순서, 주의사항과 대응방법 (0) | 2023.02.18 |
[Java] Try-with-resource 케이스별 동작순서 (0) | 2022.12.25 |
최근댓글