Back-end/JAVA,Spring

[java] Try-with-resource 문이란? 자동 자원반납.

cheersHena 2021. 5. 20. 09:42
반응형

 

자바를 이용해 외부 자원에 접근하는 경우 주의점은 외부자원을 사용한 뒤 반드시 반납을 해주어야 한다는 점이다.

 

파일로 예를들면 파일 출력을 위해서 하드디스크에 저장되어 있는 파일의 내용을 메모리로 가져와야 하는데

파일의 내용을 모두 메모리에 올리는것이 부담인 경우가 많음.

때문에 많은 프로그래밍 언어들이 파일에 대해서 입출력 스트림을 연결한다.

즉,  File 인스턴스를 생성하는 순간 파일의 모든 내용이 메모리에 올라오는 것이 아니라 스트림을 연결하여 언제든지 원하는 부분의 원하는 만큼 내용을 읽어 들일수 있도록 하는 것이다. 

이 때 연결한 Stream을 자원이라 하고 이것은 시스템에서 제공 해주는 것.(운영체제가 제공)

자원반납과 finally

1. 자원반납 문제

param = new Object(); //자원할당
param.work();
param.close(); //자원 반납 

위 코드에서 작업(); 메소드가 에러없이 실행된 경우라면 close(); 메소드가 정상적으로 순차 작동하면서 자원을 반납하게 된다. 하지만 작업(); 메소드에서 에러(예외상황)가 발생하게 된다면 close(); 메소드가 실행되지 않게 되면서 자원을 반납하지 못하는 문제가 발생하게 된다.

 

2. finally 블럭의 close();

parma1 = null;
param2 = null;

try {
 param1 = new Object1();
 param2 = new Object2();
 param1.work();
 param2.work();
 ...
 
}finally{ //무조건 실행 
 if(param1 != null){
  param1.close(); //자원반납 
  param2.close(); //자원반납 
  }
}

위 코드처럼 finally 블럭 안에 close() 메소드를 쓰면 예외과 관계없이 무조건 실행되기 때문에 어떠한 상황에서든 결론적으로 자원의 반납이 가능하다. 

 

 

 

try - with - resource 문법과 자원반납.

JAVA 1.7 부터 추가된 try wirh resource 문법을 사용하면 훨씬 간결하게 자원반납 문제를 해결할 수 있게 되었다.,

try의 ()블럭에 resource 객체 구문이 들어간다. 

1. try with resource문법.

try (param = new OBject()){
 ...
} catch(Exception e) {
 ...
}

try with resource 에서는 try() 내에서 자원할당을 하면 자동으로 close() 메소드가 호출이 된다.

때문에 finally 에서 close 해주는 과정을 생략해도 된다.

 

ex)

try (FileInputStream fis = new FileInputStream("file.txt")){
 ...
} catch(IOException e) {
 ...
}

예제코드의 경우 try() 블록이 정상실행 완료 또는 예외 발생시에도 

자동으로 FileOutputStream의 close() 메소드가 호출된다. 

즉, try()블록에서 예외가 발생하면, 우선 close() 로 리소스를 닫은 후, catch() 블록으로 넘어간다. 

 

 

자원할당이 여러개인 경우 세미콜론으로 여러개를 구현할 수 도 있고 중첩 try 문에서도 사용가능하다.

 

ex) 

try (param1 = new Object1(); param2 = new Object2()) {
 ...
 try (param3 = new Object3()) {
  ...
 }
}

 

실행로직이 try() 블럭을 빠져나갈때, 자원객체의 close() 메소드가 자동으로 호출된다.

즉, try with resource 구문 사용시 예외가 발생하는 경우 jvm 이 자동으로 close()를 호출하여 자원을 반납시켜준다.

이때 try() 안의 해당객체는 AutoCloseable 인터페이스를 구현한 객체여야 한다.

 

* 자동 close() 시 예외 발생경우.

만약 자동 close()시에도 예외가 발생했다면 발생한 예외를 입출력 처리 시 발생한 예외에 담아 던지게 된다.

예외를 최종적으로 한개만 catch문으로 던져질 수 있는데 closeException은 강제로 억제(suppressed) 되었기 때문에 Suppressed 라는 문구를 예외메세지 앞에 붙여주게 된다.

 

 

try with resource 사용 조건 -  AutoCloseable 인터페이스

 

try with resource 구문을 통해 자동 자원반납을 지원하기 위해서는 해당 객체가 AutoCloseable 인터페이스를 구현해야 한다. 이유는 AutoCloseable 은 다음과 같이 정의되어 있는데 예외 발생시 jvm이 구현된 close(); 메소드를 호출하기 때문이다.

public interface AutoCloseable {
 void close() throws Exception;
}

코드 처럼 AutoCloseable 인터페이스에는 close() 메소드가 정의되어 있고, try with resouce 는 이곳의 close() 메소드를 자동 호출하는 것이다. 

 

ex) AutoCloseable 구현 클래스 

class MyResource implements AutoCloseable {
    public void MyResource() {
        System.out.println("자원이 할당됨");
    }
 
    public void work() throws Exception {
        System.out.println("작업 중 에러 발생");
        throw new Exception();
    }
 
    @Override
    public void close() throws Exception {
        System.out.println("자원이 반납됨");
    }
}
 
 
public class Example4 {
 
    public static void main(String[] args) throws Exception {
        try (MyResource resource = new MyResource()) {
            resource.work();
        }
    }
}
 

다음코드를 실행해보면 resource.work()를 실행했는데, "작업 중 에러 발생" 이 아닌 "자원이 반납됨"

이 출력된다. 즉, close() 메소드가 자동으로 실행되었음을 알 수 있다 !! 

 

 

 

 

반응형