1. try-finally
사용한 자원을 제대로 닫아주기 위해 전통적으로 try-finally를 사용해왔다.
- finalizer는 안전망의 역할로 제한적으로 사용된다.
* try-finally - 더이상 자원을 회수하는 최선의 방책이 아니다!
변경전 firstLineOfFile.java
static void firstLineOfFile(String src, String dst) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
br.close();
}
}
나쁘지 않지만, 자원을 하나 더 사용한다면 어떨까?
개선된 firstLineOfFile.java
static void firstLineOfFile(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 {
if (out != null) out.close();
}
} finally {
if (in != null) in.close();
}
}
try-finally를 사용하여 자원을 닫아줄 때의 문제는 다음과 같다.
- 사용 자원이 여러 개인 경우 코드가 중첩되어 지저분해진다.
- 예외 처리를 위해 finally 블럭에서 특정 자원이 null이 아닐 때close()하는 조건문 등.
- try 블록에서 예외가 발생했을 때 finally 블록의close()에서도 두 번째 예외가 발생하는 경우.
- 두 번째 예외로 인해 첫 번째 예외 정보가 남지 않아 디버깅이 어려워진다.
2. try-with-resources
* try-with-resources - 자원을 회수하는 최선책!
TopLineWithDefault.java
tatic String firstLineOfFile(String path, String defaultVal) {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
} catch (IOException e) {
return defaultVal;
}
}
AutoCloseable 인터페이스를 구현한 자원은 try-with-resources를 통해 간단하게 관리된다.
try 블록의 작업이 완료되거나 예외가 발생했을 때 자동으로close()가 호출되어 자원이 해제된다.
만약readLine()과close()모두 예외가 발생하면readLine()예외가 기록된다.
그러나close()예외 정보는 버려지지 않고readLine()예외에 담아진(suppressed)된 상태이기 때문에 언제든 확인할 수 있다.
Java 8 까지는 try-with-resources를 사용하기 위해 try 블록의 소괄호에 자원을 할당해야 했다.
* 복수의 자원을 처리하는 try-with-resources - 짧고 매혹적이다!
copy.java
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);
}
}
* try-with-resources를 catch 절과 함께 스는 모습
TopLineWithDefault.java
tatic String firstLineOfFile(String path, String defaultVal) {
BufferedReader br1 = new BufferedReadernew(new FileReader(path));
BufferedReader br2 = new BufferedReadernew(new FileReader(path));
try (br1; br2) {
return br.readLine();
} catch (IOException e) {
return defaultVal;
}
}
Java 9 부터는 try 블록 밖에서 선언된 객체를 참조할 수 있다.
요약
꼭 회수해야 하는 자원을 다룰 떄는 try-finally 말고, try-with-resourcs를 사용하자.
예외는 없다. 코드는 더 짧고 부명해지고, 만들어지는 예외 정보도 훨씬 유용하다.
try-finally로 작성하면 실용적이지 못할 만큼 코드가 지저분해지는 경우라도 try-with-resourcs로는
정확하고 쉽게 저원을 회수할 수 있다.
'Prodo 독서 리뷰' 카테고리의 다른 글
[Effective Java] Item 11. equals를 재정의하려거든 hashCode도 재정의하라 (0) | 2021.04.11 |
---|---|
[Effective Java] Item 10. equals는 일반 규약을 지켜 재 정의하라 (0) | 2021.04.11 |
[Effective Java] Item 8. finalizer와 cleaner 사용을 피하라 (0) | 2021.04.11 |
[Effective Java] Item 7. 다 쓴 객체 참조를 해제하라 (0) | 2021.04.11 |
[Effective Java] Item 6. 불필요한 객체 생성을 피하라 (0) | 2021.04.11 |