자바 라이브러리에는 close()
메서드를 호출해 직접 닫아줘야 하는 자원들이 많다.(InputStream
, OutputStream
,java.sql.Connection
등등)
이런 자원닫기는 클라이언트가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어지기도 한다. 이런 자원들은 보통 finalizer을 활용하고는 있지만, 그리 믿을만하지 못하다.
전통적으로 자원의 닫힘을 보장하는 수단으로 try-finally 수법을 많이 사용했다. 이 방법을 사용하면, 예외가 발생하거나 메서드에서 반환되는 경우에도 자원을 안전하게 반환할 수 있다는 장점을 가지고 있다.
static String firstLineOfFile(String path) throws IOException{
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
br.close();
}
}
여기에 문제는 br
이라는 객체자체에 문제가 생겨버리면 return br.readLine()
이 라인에서 오류가 발생하고, 마찬가지로 br.close();
이 라인에서도 오류가 발생한다.
하지만 우리가 오류를 트래킹해보면 위에 오류는 try문으로 넘어가서 finally 오류만 보이므로 첫번째 오류는 확인할 수 없게되는 문제점이 발생한다. (일반적으로 첫번째 발생한 오류를 보고싶음)
static void copy(String src, String dst) throws IOException {
InputStream 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 하나에 안담고.. 이렇게 하는거지? 에러날까봐인가?
try-with-resources
static String firstLineOfFile(String path) throws IOException{
try (BufferedReader br = new BufferedReader(new FileReader(path))){
return br.readLine();
}
}
static void copy(String src, String dst) throws IOException {
try(InputStream 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);
}
}
자연스럽게 객체의 scope를 정해두어 close() 함수를 사용하지 않고도 객체를 수거할 수 있는 아주 좋은 구조의 코드이다.
일단 두 코드 훨씬 간결하고 읽기수월하다.
앞서 말했던 br
객체에서 오류가 발생한다고 생각해보면 readLine
함수에서 오류가 발생하게 된다.