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

InputStream , OutputStream, java.sql.Connection 등

 

자원 닫기는 클라이언트가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어지기도 한다.

이런 자원 중 상당수가 안전망으로 finalizer를 사용하고 있지만, 이는 안전하지 못하다.

 

전통적으로 지금까지는 try finally가 쓰였다.
아래처럼!!

static String firstLineOfFile(String path) throws IOException{
	BufferedReader br new BufferedReader(new FileReader(path));
    try{
    	retun br.readLine();
    }finally{
    	br.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();
    }

}

이렇게 복잡한 코드가 되어버린다.

이러한 문제는 자바 7에서 제공한 try-with-resources 를 사용하면 모두 해결된다.

 

이 구조를 사용하려면 해당 자원이 AutoClosable 인터페이스를 구현해야한다.

단순히 void를 반환하는 close 메서드 하나만 덩그러니 정의한 인터페이스이다.

자바 라이브러리와 서드파티 라이브러리들의 수많은 클래스와 인터페이스가 이미 AutoCloseable을 구현하거나 확장해뒀다.

앞으로 닫아야 하는 클래스를 작성한다면 아래처럼 사용하도록 하자.

 

위의 두 코드를 try-with-resources 적용하면 아래와 같다.

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

훨씬 짧고 읽기 수월해졌다.

앞으로 기존에 사용했던 실용적이지 못한 코드는 버리고!

꼭 회수해야 하는 자원을 다룰때에는 try-with-resources 를 사용하도록 하자.

 

 

 

 

참고 : 책, 이펙티브 자바 3/E

+ Recent posts