본문 바로가기

책리뷰/이펙티브자바

[이펙티브자바] 아이템9. try-finally보다는 try-with-resources를 사용하라

728x90
반응형

자바 라이브러리에서 close메서드를 호출해 직접 자원을 닫아 줘야하는 경우가 있다.

(InputStream, OutputStream, java.sql.Connection 등..)

자원을 닫을 때 finalizer는 믿을 수 없다.

2022.02.24 - [책리뷰/이펙티브자바] - [이펙티브자바] 아이템8. finalizer와 cleaner사용을 피하라

 

전통적인 방법으로는 try-finally가 쓰였다. 

 

try-finally 구문의 문제 


static String firstLineOfFile(String path) throws IOException {
	BufferedReader br = new BufferedReader(new FileReader(path));   
    try {
    	return br.readLine();
	} finally {
    	br.close();
    }
}

위의 코드에서 readLine메서드가 예외를 던지고, close메서드도 예외를 던질 경우 두 번째 예외가 첫 번째 예외를 집어 삼킨다. 즉, 첫 번째 예외는 스택 추적 내역에 남지 않는다. (디버깅이 어려워짐) 

 

 

자원을 하나 더 사용할 경우 

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();
    }
}

 

자원이 늘어날 수록 코드는 지저분해지고 try블록과 finally블록에서 모두 예외가 발생할 때 정확한 디버깅을 할 수 없다.

 

try-with-resources


try-with-resources를 사용하려면 AutoCloseable 인터페이스를 구현해야한다.

static String firstLineOfFile(String path) throws IOException {
	try(BufferedReader br = new BufferedReader(new FileReader(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에서 발생한 예외가 기록되고 close에서 발생한 예외는 숨겨진다. 

(suppressed 숨겨졌다는 꼬리표를 달고 출력한다.)

 

❗️ 꼭 회수해야하는 자원을 다룰 때는 try-with-resources를 사용한다. 예외는 없다. 

 

728x90
반응형