이 게시글은 이것이 자바다(저자 : 신용권, 임경균)의 책과 동영상 강의를 참고하여 개인적으로 정리하는 글임을 알립니다.
- 리소스란 데이터를 제공하는 객체(DB 등)를 뜻한다.
- 리소스를 사용하기 위해선 열어야 하고, 사용이 끝나면 반드시 닫아야 한다.
- 리소스를 사용하고 닫지 않으면 불안정한 상태로 남게 된다.
try-catch-finally문
리소스를 자동으로 닫는 기본적인 방법은 try-catch-finally문에서 finally 부분에 리소스를 닫는 코드를 넣어주면 된다.
finally는 예외가 발생하든 안 하든, 메소드가 return문을 만나도 무조건 실행되기 때문이다.
FileInputStream fis = null;
try {
fis = new FileInputStream("file.tsxt");
} catch(IOException e) {
//예외 처리 코드 작성
}finally {
fis.close(); //리소스 닫기
}
try-with-resources문
try-catch-finally문과 다르게 finally문을 작성하지 않아도 된다.
이 또한 예외 발생 여부와 상관없이 리소스를 자동으로 닫아준다.
try괄호에 리소스를 여는 코드를 작성하면 try 블록이 정상적으로 실행을 완료했거나 도중에 예외가 발생하면 자동으로 리소스의 close() 메소드가 호출된다.
하지만 try-with-resources문을 사용하려면 리소스는 java.lang.AutoCloseable 인터페이스를 구현하고 해당 인터페이스의 close() 메소드를 오버라이딩(재정의) 해야 한다.
java.lang.AutoCloseable 인터페이스는 자바가 기본적으로 제공한다.
따라서 우리는 구현 객체만 만들면 된다.
MyResource.java
public class MyResource implements AutoCloseable{
//...
@Override
public void close() throws Exception {
//리소스를 닫는 코드 작성
}
}
Main.java
public class Main {
public static void main(String[] args) {
try {
MyResource fis1 = new MyResource("file1.txt");
MyResource fis2 = new MyResource("file2.txt");
}catch(IOException e) {
//예외 처리 코드 작성
}
//finally문을 작성하지 않아도 자동으로 리소스가 닫힌다.
}
}
Java 9 버전 이후부터는 외부 리소스 변수를 사용할 수 있다.
public class Main {
public static void main(String[] args) {
MyResource fis1 = new MyResource("file1.txt");
MyResource fis2 = new MyResource("file2.txt");
try (fis1; fis2){
}catch(IOException e) {
//예외 처리 코드 작성
}
}
}
아래의 예제는 try-with-resources문을 이용하여 제대로 리소스를 닫을 수 있는지를 확인하는 예제이다.
결과를 확인하면 제대로 예외가 발생해도 close() 메소드가 자동으로 호출되어 리소스를 자동으로 닫을 수 있다는 것을 확인할 수 있다.
MyResource.java
public class MyResource implements AutoCloseable {
private String name;
public MyResource(String name) {
this.name = name;
System.out.println("[MyResource(" + name + ") 열기]");
}
public String read1() {
System.out.println("[MyResource(" + name + ") 읽기]");
return "100";
}
public String read2() {
System.out.println("[MyResource(" + name + ") 읽기]");
return "abc";
}
@Override
public void close() throws Exception {
System.out.println("[MyResource(" + name + ") 닫기]");
}
}
Main.java
public class Main {
public static void main(String[] args) {
try (MyResource res = new MyResource("A")) {
String data = res.read1();
int value = Integer.parseInt(data);
} catch(Exception e) {
System.out.println("예외 처리: " + e.getMessage());
}
System.out.println();
///////////////////////////////////////////////////
try (MyResource res = new MyResource("A")) {
String data = res.read2();
//NumberFormatException 발생
int value = Integer.parseInt(data);
} catch(Exception e) {
System.out.println("예외 처리: " + e.getMessage());
}
System.out.println();
///////////////////////////////////////////////////
try (
MyResource res1 = new MyResource("A");
MyResource res2 = new MyResource("B")
) {
String data1 = res1.read1();
String data2 = res2.read1();
} catch(Exception e) {
System.out.println("예외 처리: " + e.getMessage());
}
System.out.println();
///////////////////////////////////////////////////
MyResource res1 = new MyResource("A");
MyResource res2 = new MyResource("B");
try (res1; res2) {
String data1 = res1.read1();
String data2 = res2.read1();
} catch(Exception e) {
System.out.println("예외 처리: " + e.getMessage());
}
}
}
/*
[MyResource(A) 열기]
[MyResource(A) 읽기]
[MyResource(A) 닫기]
[MyResource(A) 열기]
[MyResource(A) 읽기]
[MyResource(A) 닫기]
예외 처리: For input string: "abc"
[MyResource(A) 열기]
[MyResource(B) 열기]
[MyResource(A) 읽기]
[MyResource(B) 읽기]
[MyResource(B) 닫기]
[MyResource(A) 닫기]
[MyResource(A) 열기]
[MyResource(B) 열기]
[MyResource(A) 읽기]
[MyResource(B) 읽기]
[MyResource(B) 닫기]
[MyResource(A) 닫기]
*/