[Java] 객체 생성과 파괴 9

3709 단어 JavaJava

EFFECTIVE JAVA 3/E 책을 공부하고 정리한 글입니다.

📖 try-finally보다는 try-with-resources를 사용하라


📌 try-finally

  • 자바 라이브러리에는 close 메서드를 호출하여 직접 닫아줘야 하는 자원이 많다.
    ex> InputStream, OutputStream, java.sql.Connection 등

  • 자원 닫기는 클라이언트가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어진다.
    --> 이런 자원 중 상당수가 안전망으로 finalizer을 활용하지만, 이는 믿을만 하지 않다.
    --> 전통적으로 자원이 제대로 닫힘을 보장하는 수단으로 try-finally가 사용되었다.

// [코드 9-1] try-finally - 더 이상 자원을 회수하는 최선의 방책이 아니다!

static String firstLineOfFile(String path) throws IOEception {
	BufferedReader br = new BufferedReader(new FileReader(path));
    try{
    	return br.readLine();
    } finally {
    	br.close();
    }
}
  • 자원을 하나 더 사용한다면 지저분해진다.
// [코드 9-2] 자원이 둘 이상이면 try-finally 방식은 너무 지저분하다!

static void copy(String src, String dst) throws IOException {
	InputStream in = new FileInputStream(src);
    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 문을 사용한 앞의 두 코드에서 미묘한 결점이 존재한다.
    -- 예외는 try블록과 finally블록 모두에서 발생할 수 있는데, 만약 기기에 물리적인 문제가 생긴다면 두 번째 예외가 첫 번째 예외를 완전히 집어삼켜 버린다.
    -- 그러면 스택 추적 내역에 첫 번째 예외에 관한 정보는 남지 않게 되어 디버깅이 매우 어렵다.
    -- 이를 해결하기 위해 첫 번째 예외를 기록하도록 코드를 수정할 수는 있지만 이는 코드가 매우 지저분하게 한다.


📌 try-with-resources

  • try-finally의 문제점을 해결하기 위해, 자바 7 에서 try-with-resources를 제공한다.
    -- 이 구조를 사용하려면 AutoCloseable 인터페이스를 구현해야 한다.
    -- 이 인터페이스는 단순히 void를 반환하는 close 메서드 하나만 정의한 인터페이스 이다.
    -- 자바 라이브러리와 서드파티 라이브러리들의 수많은 클래스와 인터페이스가 이미 AutoCloseable을 구현하거나 확장해뒀다.
// [코드 9-3] try-with-resources - 자원을 회수하는 최선책!
// 코드 9-1에 try-with=resources을 적용한 코드

static String firstLineOfFile(String path) throws IOException {
	try(BufferedReader br = new BufferedReader(new FileReader(path))) {
    	return br.readLine();
    }
}
// [코드 9-4] 복수의 자원을 처리하는 try-with-resources - 짧고 매혹적이다!
// 코드 9-2에 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);
        }
}
  • 짧고 읽기 수월하고, 문제를 진단하기도 훨씬 좋다.

  • 숨겨진 예외도 스택 추적 내역에 '숨겨졌다'(getSuppressed)는 꼬리표를 달고 출력된다.
    -- 자바 7에서 Throwable에 추가된 getSuppressed 메서드를 이용하면 프로그램 코드에서 가져올 수도 있다.

  • 보통의 try-finally에서처럼 try-with-resources에서도 catch 절을 사용할 수 있다.
    -- 이 덕분에 try 문을 더 중첩하지 않고도 다수의 예외를 처리할 수 있다.

// [코드 9-5] try-with-resources를 catch 절과 함께 쓰는 모습

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를 사용하자!
코드는 더 짧고 분명해지고 생성되는 예외 정보도 훨씬 유용하다.
try-with-resources로는 정확하고 쉽게 자원을 회수할 수 있다.

좋은 웹페이지 즐겨찾기