try-catch-finally
는 우리가 흔히 예외처리를 하기 위해서 사용하는 구문중 하나이다.
보통은 예외처리가 필요한 부분을 try
에 넣고, 예외를 처리할 때는 catch
로, 그리고 자원의 해제를 finally
부분에서 진행했다.
예를 들면 아래처럼
public void catchException(){
InputStreamReader is = null;
BufferedInputStreamReader bf = null;
try {
is = new InputStreamReader(Files.newInputStream(Paths.get(path)), StandardCharsets.UTF_8);
bf = new BufferedReader(is);
String line;
while ((line = bf.readLine()) != null) {
bf.append(line).append("\n");
}
} catch (Exception e) {
System.out.println("error!");
} finally {
if(bf ! = null ) {
bf.close();
}
if(is != null){
is.close();
}
}
}
위의 코드에서는InputStreamReader
, BufferedReader
객체를 생성한 뒤에 finally
에서 모두 close 처리를 해주었다.
솔직히 귀찮다! 매번 생성한 객체들에 대해서 null 체크를 해야하고, 이를 또 close해야한다.
Java 7 부터 Try-with-Resources
구문을 지원하고 이것을 사용하면 자원을 이전처럼 굳이 하나하나 해주지 않아도 할 수 있다.
위의 코드를 Try-with-Resources
구문으로 변경해보자.
public void catchException(){
try(BufferedInputStreamReader bf = new BufferedReader(new InputStreamReader(Files.newInputStream(Paths.get(path)), StandardCharsets.UTF_8))) {
String line;
while ((line = bf.readLine()) != null) {
bf.append(line).append("\n");
}
} catch (Exception e) {
System.out.println("error!");
}
}
Try-Catch-Finally
와 다른 점이라고 하면 close가 필요한 객체들이 try 문에서 선언되며 할당된다는 점이다.
try에서 선언된 객체들은 try 문 안에서 사용이 가능하다.
만약 해당 객체들이 try문을 벗어난다면, 해당 객체들의 close 문을 호출하게 된다.
그렇기에 우리는 더 이상 close 를 명시적으로 호출하지 않아도 된다.
물론 주의해야하는 점이 있다.
자동으로 close가 호출되는 것은 AutoCloseable 을 구현한 객체에만 해당된다.
우리가 사용한 BufferedReader
객체의 상속관계를 보자.
java.lang.AutoCloseable
java.io.Closeable
java.io.Reader
java.io.BufferedReader
이처럼 BufferedReader
는 AutoCloseable 을 상속받아서 구현되어있음을 알 수 있다.
만약 위처럼 AutoCloseable
을 상속받지 않은 객체에 대해서 위처럼 사용하고 싶다면 AutoCloseable을 상속해서 close()
메서드를 오버라이드해서 구현해주면 된다.