자바 라이브러리에서는 close 메소드를 호출해 직접 닫아줘야 하는 자원들이 많음
InputStream , OutputStream , java.sql.Connection 등이 있음
자원 닫기는 클라ㅏ이언트가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어지기도 함
이러한 자원 중 상당수가 안전망으로 finalizer 를 활용하고 있지만 finalizer는 그리 믿을만하지 못함 (챕터8 참고)
전통적으로 자원이 제대로 닫힘을 보장하는 수단으로는 try-finally가 쓰였음
- try-finally 을 사용한 예제 코드이며, 최선의 방책이 아닌 코드
=================================================================================================================
static String firstLineOfFile(String path)throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try{
return br.readLine();
}finally{
br.close();
}
}
=================================================================================================================
- 위의 방식에서 자원을 추가로 사용한 코드
=================================================================================================================
static void copy(String src, String dst)throws IOException {
Input Stream in new FileInputStream(src);
try{
OutputStream out = new FileOutputStream(dst);
try{
byte[] buf = new byte[BUFFER_SIZE];
int n;
while((n = in.read(buf))>=0){
out.write(buf,0,n);
}
}finally{
out.close();
}
}finally{
in.close();
}
}
=================================================================================================================
위와같이 작성했을 경우 예외는 try 블록과 finally 블록에서 모두 발생할 수 있는데, 기기에 물리적인 문제가 생긴다면 firstLineOfFile 메서드 안에서
readLine 메소드가 예외를 던지고 같은 이유로 close 메소드도 실패함
이러한 상황이라면 두번째 예외가 첫 번째 예외를 완전이 집어삼켜 버림
그러면 스택 추적 내영에서 첫 번째 예외에 관한 정보는 남지 않게 되어, 실제 시스템에서의 디버깅을 몹시 어렵게 함
이러한 문자들은 try - with - resources 를 사용하면 해결 할 수 있음
이 구조를 사용하려면 AutoCloseable 인터페이스를 구현해야 함.
단순히 void를 반환하는 close 메소드를 하나만 덩그러니 정의한 인터페이스이며,
자바 라이브러리와 서드파티 라이브러리들의 수많은 클래스와 인터페이스가 이미 AutoCloseable을 구현하거나 확장해줬음
- try-with-resources 코드
=================================================================================================================
static String firstLineOfFile(String path)throws IOException {
try(BufferedReader br = new BufferedReader(new FileReader(path))){
return br.readLine();
}
}
=================================================================================================================
- 복수의 자원을 처리하는 try-with-resources 코드
=================================================================================================================
static void copy(String src, String dst)throws IOException {
try(Input Stream in new FileInputStream(src);
OutputStream out = new FileOutputStream(dst)){
byte[] buf = new byte[BUFFER_SIZE];
int n;
while((n = in.read(buf))>=0){
out.write(buf,0,n);
}
}
}
=================================================================================================================
위에 작성한 try-with-resources 코드가 짧고 읽기 수월할 뿐 아니라 문제를 진단하기도 훨씬 좋다.
catch까지 적용하면 아래의 코드가 된다
- try-with-resources 코드에 cathc 까지 적용
=================================================================================================================
static String firstLineOfFile(String path, String defaultVal) {
try(BufferedReader br = new BufferedReader(new FileReader(path))){
return br.readLine();
}catch(IOException e){
return defaultVal;
}
}
=================================================================================================================
꼭 회수해야 하는 자원을 다룰 때는 try-finally 말고, try-with-resources 를 사용하자.
예외 없이 코드는 더 짧고 분명해지고, 만들어지는 예외정보도 훨씬 유영해진다.
finally로 작성하면 실용적이지 못할 만큼 코드가 지저분해지는 경우라도, try-with-resources로는 정확하고 쉽게 자원을 회수할 수 있다.