리소스 자동 해제 예외 처리
finally{} 블록은 '항상 실행해야 하는 기능이 있을 때 사용하는 블록' 이다
finally{} 블록의 가장 대표적인 기능은 리소스를 해제하는 것이다. (자원반납)
예를들어 수정하기 위해 열어둔 파일이 있다면 이 파일을 닫아야 다른 프로그램이 이 파일을 사용할 수 있다.
메모리에 엄청난 크기의 객체를 만들어 놓고 사용했을 때도 사용이 완료되면 메모리 공간을 확보하기 위해 리소스를 해제해야 한다.
자바에서 리소스해제가 꼭 필요한 대표적인 예로 자바 입출력 리소스를 들 수 있다. 다음 예제를 살펴보자
InputStreamReader is = null;
try {
is = new InputStreamReader(System.in);
System.out.println(is.read());
} catch (IOException e){
// 예외 처리
} finally {
if(is != null){
try {
is.close();
} catch (IOException e){
//예외처리
}
}
}
try블록에서 객체를 생성하고 사용한 후에 finally블록에서 close()메서드로 자원을 반납한 것을 알 수 있다.
대부분 자바 입출력코드는 이러한 구조를 가지고 있다.
try(리소스 자동 해제가 필요한 객체 생성){
// 예외 발생 가능 코드
} catch 예외 클래스명 참조 변수명){
// 해당 예외가 발생했을 때 처리하는 블록
} finally {
// 예외 발생 여부에 상관없이 무조건 실행하는 블록
}
기존 예외 처리 구문과의 차이점은 try(){}구문에도 소괄호가 포함된다는 것이다.
이 소괄호 안에서 자동으로 리소스를 반납해야 할 객체를 생성하면 예외 처리 구문이 실행이 끝났을 때 리소스가 자동으로 해제된다.
예외 처리 구문이 완료되면 try(){}블록 소괄호 안에서 생성된 객체 내부의 close()메서드를 자동으로 호출함으로써 리소스를 자동으로 해제한다.
즉, finally{} 블록에서 하던일(객체가 null 이 아니면 close()메서드 호출)을 자동으로 처리해 준다는 것이다.
아래 예제는 위의 예를 리소스 자동 해제 예외 처리 구문으로 변경한 것이다.
try (inputStreamReader is = new InputStreamReader(System.in);){
System.out.println(is.read());
} catch (IOException e){
// 예외처리
}
리소스가 정말로 해제되었는지 확인하기 위해 다음 예를 살펴보자
import java.io.IOException;
import java.io.InputStreamReader;
public class TryWithResource_1 {
public static void main(String[] args) {
System.out.println("문자를 입력하세요!");
//참고. System.in 리소스를 해제하면 더이상 콘솔입력이 불가
//#1. 자동리소스 해제
try(InputStreamReader isr1 = new InputStreamReader(System.in);){
char input = (char)isr1.read();
System.out.println("입력글자 = " + input);
}
catch(IOException e) {
e.printStackTrace();
}
//#2. 수동리소스 해제
InputStreamReader isr2=null;
try{
isr2 = new InputStreamReader(System.in);
char input = (char)isr2.read();
System.out.println("입력글자 = " + input);
}
catch(IOException e) {
e.printStackTrace();
}
finally {
//리소스 해제 구문
if(isr2!=null) {
try { //리소스 해제
isr2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
실제로 try - catch로 리소스가 해제되는지 확인하기 위해 system.in을 사용했다.
첫 번째 블록 코드가 실행되면 입력받은 문자를 받아 그대로 출력한다.
try-catch구문을 끝낼 때 리소스를 해제하기 때문에 이후에는 콘솔 입력을 사용할 수 없다
두번째 코드를 실행하는 과정에서 예외가 발생한다는 것을 알 수 있다.
// result
문자를 입력하세요!
a
입력글자 = a
java.io.IOException ERROR
그렇다면 try구문 소괄호 안에 생성된 객체 내부의 close()메서드가 포함된 것을 보장하려면 autocloseable 인터페이스를 사용하면 된다.
리소스 자동 해제를 위한 클래스는 반드시 AutoCloseable 인터페이스를 구현해야한다.
해당 인터페이스 내부에는 close()추상메서드가 포함되어 있어 AutoCloseable인터페이스를 구현하여 내부에 close()메서드를 포함하고 있는 클래스에 한해 리소스 자동해제 기능이 제공된다.
class A implements AutoCloseable {
String resource;
A(String resouce){
this.resource = resouce;
}
@Override
public void close() throws Exception {
if(resource!=null) {
resource=null;
System.out.println("리소스가 해제되었습니다.");
}
}
}
public class TryWithResource_2 {
public static void main(String[] args) {
//#1. 리소스를 사용하고 finally에서 리소스 수동 해제하기
A a1 = null;
try {
a1 = new A("특정파일");
} catch (Exception e) {
System.out.println("예외처리");
} finally {
//리소스 수동 해제
if(a1.resource!=null) {
try {
a1.close();
} catch (Exception e) {}
}
}
//#2. 자동 리소스 해제
try (A a2 = new A("특정파일");) {
} catch (Exception e) {
System.out.println("예외처리");
}
}
}
'Language > Java' 카테고리의 다른 글
[Java] 쓰레드, 멀티쓰레드 (0) | 2022.04.05 |
---|---|
[Java] 예외 전가 (throws) (0) | 2022.04.05 |
[Java] 예외 처리 (0) | 2022.04.04 |
[Java] 이너 인터페이스 (0) | 2022.04.03 |
[Java] 인터페이스 타입의 입력 매개변수 전달 (0) | 2022.04.03 |