자바에서 스트림이나 커넥션같은 자원은 다 사용한 후에 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 인터페이스만 상속받으면 가능합니다.

 

https://docs.oracle.com/javase/9/docs/api/java/io/BufferedInputStream.html

위 예시 코드에서 소개드렸던 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이 전파된다는 차이가 있습니다.

 

 

 

반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기