-
Item 9. try-finally보다는 try-with-resources를 사용하라Book/Effective Java 3E 2022. 10. 13. 08:30반응형
자바 라이브러리에는 close 메서드를 호출해 직접 닫아줘야 하는 자원이 많습니다. InputStream, OutputStream, java.sql.Connection 등이 좋은 예입니다. 자원 닫기는 클라이언트가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어지기도 합니다. 이런 자원 중 상당수가 안전망으로 finalizer를 활용하고 있지만 finalizer는 그리 믿을만하지 못합니다(Item 8).
전통적으로 자원이 제대로 닫힘을 보장하는 수단으로 try-finally가 쓰였습니다. 예외가 발생하거나 메서드에서 반환되는 경우를 포함해서 말입니다.
package effectivejava.chapter2.item9.tryfinally; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class TopLine { // 코드 9-1 try-finally - 더 이상 자원을 회수하는 최선의 방책이 아니다! static String firstLineOfFile(String path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { br.close(); } } public static void main(String[] args) throws IOException { String path = args[0]; System.out.println(firstLineOfFile(path)); } }
package effectivejava.chapter2.item9.tryfinally; import java.io.*; public class Copy { private static final int BUFFER_SIZE = 8 * 1024; // 코드 9-2 자원이 둘 이상이면 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(); } } public static void main(String[] args) throws IOException { String src = args[0]; String dst = args[1]; copy(src, dst); } }
다음은 자바 7에 도입된 try-with-resources를 사용해 코드를 재작성한 예입니다. 이 구조를 사용하려면 해당 자원이 AutoCloseable 인터페이스를 구현해야 합니다. 단순히 void를 반환하는 close 메서드 하나만 덩그러니 정의한 인터페이스입니다. 자바 라이브러리와 서드파티 라이브러리들의 수많은 클래스와 인터페이스가 이미 AutoCloseable을 구현하거나 확장해뒀습니다. 닫아야 하는 자원을 뜻하는 클래스를 작성한다면 반드시 AutoCloseable을 구현해야 합니다.
package effectivejava.chapter2.item9.trywithresources; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class TopLine { // 코드 9-3 try-with-resources - 자원을 회수하는 최선책! static String firstLineOfFile(String path) throws IOException { try (BufferedReader br = new BufferedReader( new FileReader(path))) { return br.readLine(); } } public static void main(String[] args) throws IOException { String path = args[0]; System.out.println(firstLineOfFile(path)); } }
package effectivejava.chapter2.item9.trywithresources; import java.io.*; public class Copy { private static final int BUFFER_SIZE = 8 * 1024; // 코드 9-4 복수의 자원을 처리하는 try-with-resources - 짧고 매혹적이다! 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); } } public static void main(String[] args) throws IOException { String src = args[0]; String dst = args[1]; copy(src, dst); } }
꼭 회수해야 하는 자원을 다룰 때는 try-finally 말고, try-with-resources를 사용하자.
예외는 없다. 코드는 더 짧고 분명해지고, 만들어지는 예외 정보도 훨씬 유용하다.
try-finally로 작성하면 실용적이지 못할 만큼 코드가 지저분해지는 경우라도, try-with-resources로는 정확하고 쉽게 자원을 회수할 수 있다.
[참고 정보]
이펙티브 자바 Effective Java 3/E 도서 [조슈아 블로크 저]
반응형'Book > Effective Java 3E' 카테고리의 다른 글
Item 11. equals를 재정의하려거든 hashCode도 재정의하라 (2) 2022.10.18 Item 10. equals는 일반 규약을 지켜 재정의하라 (0) 2022.10.17 Item 8. finalizer와 cleaner 사용을 피하라 (0) 2022.10.13 Item 7. 다 쓴 객체 참조를 해제하라 (0) 2022.10.12 Item 6. 불필요한 객체 생성을 피하라 (0) 2022.10.10