close해주어야 하는 객체들
InputStream, OutputStream, java.sql.Connection...
close()메서드를 호출하여 닫아주어야 대표적인 객체들이다. 외부 자원과 연동되어있기 때문에 닫아주지 않으면 예외가 발생하곤 한다. 안전망으로 finalizer를 사용하지만, 별로 믿음직스러운 수단은 아니다.(item 8) 전통적으로 사용되던 try-finally가 많이 쓰였다.
try-finally
// try-finally - No longer the best way to close resources!
static String firstLineOfFile(String path) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
br.close();
}
}
Java
복사
하지만 닫아주어야 할 자원이 둘 이상이면 코드가 매우 지저분해진다.
// try-finally is ugly when used with more than one resource!
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 이 null이라면..? NPE
if(out != null){
out.close();
}
}
} finally {
in.close();
}
}
Java
복사
개발실력의 숙련 여부와 상관없이 실수할 확률이 매우 높아진다. 또한 해당 코드는 out객체가 고장난 경우, out.close()에서 발생한 예외가 out.write()에서 발생한 예외를 집어삼킬 것이므로 디버깅을 힘들게 만든다.(먼저 발생한 예외를 표현할 방법은 있지만 코드가 매우 지저분해진다.)
try-with-resources
자바 7부터는 try-with-resources이 등장하여 문제가 해결되었다. 이 구조를 사용하려면 해당 자원이 AutoCloseable 인터페이스를 구현해야 한다. 만약 close 해야하는 클래스를 작성하면, AutoCloseable을 구현하도록 하자.
// try-with-resources - the the best way to close resources!
static String firstLineOfFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(
new FileReader(path))) {
return br.readLine();
}
}
Java
복사
한 줄로도 사용 가능
// try-with-resources on multiple resources - short and sweet
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);
}
}
Java
복사
여러 자원도 멀티 라인으로 사용 가능
try-with-resources 에선 앞서 이야기했던 readLine과 close에서 모두 예외가 발생하더라도, 앞선 예외가 Supperessed 꼬리표를 달고 스택트레이스에 등장하기 때문에 디버깅하기가 쉬워진다. catch문을 추가하여 별도의 예외처리도 수행할 수 있다.
// try-with-resources with a catch clause
static String firstLineOfFile(String path, String defaultVal) {
try (BufferedReader br = new BufferedReader(
new FileReader(path))) {
return br.readLine();
} catch (IOException e) {
return defaultVal;
}
}
Java
복사
또한 java9 부터는 try 블록 밖에서 선언 되었더라도, final 객체라면 활용할 수 있도록 하는 기능이 추가되었다.
final Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"))
try (scanner;writer) {
// omitted
}
Java
복사
용어정리
한글명 | 영어명 |
간과하다 | overlook |
거의 | merely |
더럽혀지다 | sully |
고안하다 | contrive |
억눌린, 감춰진 | suppressed |