...
자바 Resource의 예외 처리
보통 resource란 외부의 데이터(DB, Network, File)를 일컫는다.
이런 resource들은 자바 내부에 위치한 요소들이 아니기 때문에, 이러한 프로세스 외부에 있는 데이터에 자바 코드에서 접근하려고 할 때 문제(예외)가 발생할 수 있는 여지가 존재한다.
특히나 이런 입출력에 관련된 resource들에 접근해서 사용하고 나면 닫는 것이 굉장히 중요하다. 예를들어 파일에 접근해 파일을 열고 내용을 쓰고 난후 꼭 닫아 주어야 한다. 왜냐하면 어떤 resource를 사용하다가 다른곳에서 같은 resource에 접근해 막 사용하다 보면 꼬일 수 있기 때문이다.
예를 들어 다음과 같이 외부 텍스트 파일에 접근해서 내용을 쓰고 닫는 로직을 자바에서 구현하였다.
만일 data.txt 라는 파일을 읽는데 예상치 못한 오류가 발생할 가능성이 있기 때문에, Checked Exception인 IOException을 불러와 예외처리 하였다. 그리고 마지막에 외부 resource는 사용했으면 반드시 닫아주어야 하기 때문에 finally문으로 파일을 close() 처리 하였다.
import java.io.FileWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
FileWriter file = null;
try {
file = new FileWriter("data.txt");
file.write("Hello World");
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
file.close();
// 작업중에 예외가 발생하더라도 파일이 닫히도록 finally블럭에 넣음
// 근데 close()가 예외를 발생시키면 문제가 됨
}
}
}
하지만 위의 코드를 실행해보면 컴파일 에러가 뜬다. 왜냐하면 파일을 닫는 동작 코드 자체도 IOException 예외가 일어날 수 있는 동작이기 때문에 이부분도 예외 처리를 해주어야 하기 때문이다.
따라서 최종적으로 파일을 열어 쓰고 닫는 코드는 다음과 같이 구성되게 된다.
import java.io.FileWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
FileWriter file = null;
try {
file = new FileWriter("data.txt");
file.write("Hello World");
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
// close()에서 발생하는 예외를 처리하기 위해서 아래와같이 바꿀수도 있지만 코드가 복잡해져서 좋지않다.
try {
file.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
코드 안정성은 그렇다 쳐도 겨우 파일을 열고 닫는데는 코드 3줄이면 될것을 괜히 예외처리한다고 덕지덕지 붙여나 굉장히 가독성이 안좋아 졌다.
그래서 자바 개발진도 이에 대해 문제를 인식하고 좀 더 간편하게 구성할 수 있는 새로운 예외처리 문법을 자바 7버전에 내놓았는데 이 다음에 배울 try - with - resource 문이다.
Try with Resource 문
JDK1.7부터 try - with - resources 문이라는 try - catch 문의 변형 문법이 새로 추가되었다.
try - with - resources 문은 주로 입출력(I/O)과 관련된 클래스를 사용할 때 굉장히 유용하다. 입출력에 사용한 객체를 자동으로 반환시켜주기 때문이다.
사용법은 아래와 같이 try 블록에 괄호()를 추가하여 파일을 열거나 자원을 할당하는 명령문을 명시하면, 해당 try 블록이 끝나자마자 자동으로 파일을 닫거나 할당된 자원을 해제해 준다.
try (파일을 열거나 자원을 할당하는 명령문) {
...
}
따라서 위의 파일IO 코드를 try - with - resources 문으로 리팩토링하면 다음과 같이 된다.
try - with - resources 문의 괄호() 안에 객체를 생성하는 문장을 넣으면, 따로 close() 를 호출하지 않아도 try 블럭을 벗어나는 순간 자동적으로 close() 가 호출된다. 그리고 다음에 catch 블럭 또는 finally 블럭이 수행된다
import java.io.FileWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try (FileWriter file = new FileWriter("data.txt")) { // 파일을 열고 모두 사용되면 자동으로 닫아준다
file.write("Hello World");
} catch (IOException e) {
e.printStackTrace();
}
}
}
또한 괄호 안에 IO객체 문장을 두개 이상 넣어줄수도 있다.
이때는 세미콜론으로 각 문장을 구분해 주어야 한다.
// try 괄호 안에 두문장 이상 넣을 경우 ';'로 구분한다.
try(
FileInputStream fis = new FileInputStream("a.txt");
DataInputStream dis = new DataInputStream(fis)
) {
while(true){
score - dis.readInt();
System.out.println(score);
sum += score;
}
} catch (EOFException e){
System.out.println("점수의 총합은 " + sum + "입니다.");
} catch (IOException ie){
ie.printStackTrace();
}
AutoCloseable 인터페이스
좀더 깊게 들어가자면, 어떠한 클래스가 try - with - resources 문으로 사용될 수 있기 위해서는 AutoCloseable 인터페이스를 구현 받아야 한다.
위에서의 FileWriter 클래스 역시 클래스 정의문에 들어가면 AutoCloseable 라는 인터페이스를 구현한 것을 볼 수 있다. 이 AutoCloseable을 가지고 있다면 try-with-resource 문법을 사용할 수 있는 것이다.
# 참고자료
https://www.youtube.com/watch?v=I4XrVgCzKM4
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.