본문 바로가기

자바☕/이펙티브 자바

이펙티브 자바 읽고 정리해보기 9.

728x90

아이템 9. try-finally보다는 try-with-resources를 사용하라

 

자바의 InputStream, OutputStream, java.sql.connection 등은 close 메서드를 통해 닫아줘야 하는 자원의 대표적인 사례로, 안전망으로 clener(finalizer)가 구현되어 있으나, 항상 기대처럼 동작하지 않는다

https://cdaosldk.tistory.com/343

 

이펙티브 자바 읽고 정리해보기 8.

아이템 8. finalizer와 cleaner(자바 8 이전 : finalizer, 8 이후 : cleaner 즉 동일) 사용을 피하라 finalizer는 오동작, 낮은 성능, 이식 문제를 야기할 수 있다. 그래서 자바 9부터는 deprecated 되었으며, cleaner

cdaosldk.tistory.com

자원 닫기를 보장하기 위해 많이 사용하는 방식이 try-finally로, 예외 발생 및 반환값 발생 시를 포함해 자원의 닫힘을 보장한다

static String firstLineOfFile(String path) throws IOException {
	BufferedReader br = new BufferedReader(new FileReader(path));
    try {
    	return br.readLine();
  	} finally {
    	br.close();
    }
}
static void copy(String src, String dst) throws IOException {
	InputStream in = new FileInputStream(src);
    try {
    	OutputStream out = new FileInputStream(dst);
        try {
        	byte[] buf = new byte[BUFFER_SIZE];
            int n;
            while((n = in.read(buf)) >= 0)
            	out.write(but, 0, n);
        } finally {
        	out.close();
        }
    } finally {
    	in.close();
    }
}

try-finally 구문을 사용한 위의 두 예제도 발생할 수 있는 결점이 있는데, firstLineOfFile 메서드 호출 간 입출력 기기 등에 물리적인 사고가 발생할 경우 readLine()이 예외를 던지고, close() 메서드도 같은 이유로 실패하게 된다. 두 번의 실패가 있었지만, 두 번째 예외만 스택 추적 기록에 남아 디버깅을 어렵게 한다(임의로 첫 번째 예외를 남기게 코드를 짤 수 있지만 비효율적이다)

 

이와 같은 문제는 try-with-resource 구문으로 해결이 가능하다. 이 구조를 사용하기 위해선 해당 자원이 AutoCloseable 인 터페이스를 구현해야 한다

static String firstLineOfFile(String path) throws IOException {
	try(BufferedReader br = new BufferedReader(
    	new FileReafer(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);
    }
}

코드 가독성도 개선되었으며, 첫 번째 예제의 readLine() 메서드와 (AutoCloseable을 구현한)close() 메서드가 동시를 예외를 발생시키는 경우 readLine() 메서드만 로그에 기록되므로, 디버깅의 난이도를 낮출 수 있고, 숨겨진 예외 기록도 "suppressed"라는 꼬리표와 함께 출력된다(숨겨진 기록을 보려면, Throwable.getSuppressed()를 호출하면 된다)

 

try-with-resource 구문에도 catch절을 사용해 다수의 예외를 처리할 수 있다

static String firstLineOfFile(String path, String defalutVal) {
	try (BufferedReader br = new BufferedReader(
    		new FileReader(path))) {
        return br.readLine();
    } catch (IOException e) {
    	return defaultVal;
    }
}
728x90