Try-with-resources 동작원리 및 작동순서  

 

예시 코드를 통해 알아보겠습니다. 아래 코드는 AutoClosable 인터페이스를 상속받는 AutoClosableResource 클래스를 선언되어 있습니다. 생성자와 doOp메서드가 있고, AutoClosable을 상속받아 오버라이딩한 close 메서드가 있습니다.

 

public class AutoClosableResource implements AutoCloseable {

    private String name = null;
    private boolean throwExceptionOnClose = false;

    public AutoClosableResource(String name, boolean throwExceptionOnClose) {
        this.name = name;
        this.throwExceptionOnClose = throwExceptionOnClose;
    }

    public void doOp(boolean throwException) throws Exception {
        System.out.println("Resource " + this.name + " doing operation");
        if(throwException) {
            throw new Exception("Error when calling doOp() on resource " + this.name);
        }
    }

    @Override
    public void close() throws Exception {
        System.out.println("Resource " + this.name + " close() called");
        if(this.throwExceptionOnClose){
            throw new Exception("Error when trying to close resource " + this.name);
        }
    }
}

 

 

    public AutoClosableResource(String name, boolean throwExceptionOnClose) {
        this.name = name;
        this.throwExceptionOnClose = throwExceptionOnClose;
    }

생성자에는 출력할 자원의 이름과, 리소스를 닫을때 Exception을 발생시킬지 여부를 받고있습니다.

 

 

  Exception이 발생하지 않는 경우와 처리순서  

 

아래 코드는 tryWithResourcesSingleResource 메서드와 main 메서드로 구성되어 있습니다. 먼저 둘다 Exception이 발생하지 않는 경우 입니다.

public static void main(String[] args){
    try {
        tryWithResourcesSingleResource();
    } catch (Exception e) {
        e.printStackTrace();
        Throwable[] suppressed = e.getSuppressed();
    }
}

public static void tryWithResourcesSingleResource() throws Exception {
    try(AutoClosableResource resourceOne = new AutoClosableResource("One", false)) {
        resourceOne.doOp(false);
    }
}

 

이 경우에는 정상적으로 수행하고 닫을 때 리소스만 반환 됩니다.

 

 

  1개의 Exception이 발생하는 경우와 처리순서  

    // 1. 블럭내에서 호출될 때만 Exception 발생
    try(AutoClosableResource resourceOne = new AutoClosableResource("One", false)) {
        resourceOne.doOp(true);
    }
    
    // 2. 닫을때만 Exception 발생
    try(AutoClosableResource resourceOne = new AutoClosableResource("One", true)) {
        resourceOne.doOp(false);
    }

 

 1번의 경우 리소스는 정상적으로 닫히며 호출부에서 발생한 Exception이 전파됩니다. 2번은 리소스를 닫는데 실패하면서 발생한 Exception이 main 메서드로 전파됩니다.

 

public static void main(String[] args){
    try {
        tryWithResourcesSingleResource();
    } catch (Exception e) {
        e.printStackTrace();
        Throwable[] suppressed = e.getSuppressed();
    }
}

두 Exception 모두 main 메서드로 전파됩니다. 1개의 Exception만 전파되었기 때문에 getSuppressed로 받은 Throwable 배열의 size는 0입니다.

 

 

  2개 이상의 Exception이 발생하는 경우와 처리순서  

    try(AutoClosableResource resourceOne = new AutoClosableResource("One", true)) {
        resourceOne.doOp(true);
    }

 하나의 자원이 블럭안에서 호출될 때 그리고 닫힐 때, 둘 다 Exception이 발생하도록 파라미터를 설정되어 있습니다. 

 

자바 메서드에서는 호출당 1개의 Exception만 전파되어야 하기 때문에, 이 경우에는 첫 번째 발생한 Exception만 전파합니다. 이 경우 블럭안에서 발생한 Exception이 먼저기 때문에 전파되고, 닫으면서 발생한 Exception은 getSuppressed로 받을 수 있습니다. 

 

 

 

  2개 이상의 리소스에서 Exception이 발생하는 경우와 처리순서   

 

main문은 같고 메서드 내에 두개의 리소스가 try-with-resources 구문에 선언되고 호출한 코드 입니다.

public static void main(String[] args){
    try {
        tryWithResourcesTwoResources();
    } catch (Exception e) {
        e.printStackTrace();
        Throwable[] suppressed = e.getSuppressed();
        System.out.println("suppressed = " + suppressed);
    }
}

public static void tryWithResourcesTwoResources() throws Exception {
    try(AutoClosableResource resourceOne = new AutoClosableResource("One", true);
        AutoClosableResource resourceTwo = new AutoClosableResource("Two", true)
    ){
        resourceOne.doOp(true);
        resourceTwo.doOp(false);
    }
}

 

 이 때 main 메서드로 전파되는 Exception은 resourceOne이 try 구문 블럭에서 호출할 때 발생된 Exception 입니다. 나머지 닫히면서 발생한 Exception 두개는 suppressed 변수에 배열로 저장됩니다.

 

 여러개의 리소스가 닫히는 상황에서 1개의 리소스에서 Exception이 발생하면, 나머지 리소스는 정상적으로 닫힙니다. 모든 리소스를 닫은 후에 실패한 리소스의 Exception만 호출 스택 위로 전파됩니다.

 

 

    try(AutoClosableResource resourceOne = new AutoClosableResource("One", true);
        AutoClosableResource resourceTwo = new AutoClosableResource("Two", true)
    ){
        resourceOne.doOp(true);
        resourceTwo.doOp(true);
    }

 이렇게 resourceOne, resourceTwo가 각각 try 구문과 리소스를 닫을 때 둘다 Exception을 발생시키면 어떻게 예외가 전파될지도 알아보겠습니다.

 

 이 경우에는 먼저 호출된 resourceOne이 try 구문 블럭에서 발생시킨 Exception이 main문으로 전파되며, 나머지 세개의 Exception은 suppressed 변수에 배열로 저장됩니다.

 

 

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