내 세상

[Java] Effective Java 3/e - Item 9) try-finally 보다는 try-with-resoucres를 사용하라 본문

Language/Java

[Java] Effective Java 3/e - Item 9) try-finally 보다는 try-with-resoucres를 사용하라

sga8 2021. 12. 3. 16:36
728x90
반응형

Java Library에는 close 메서드를 호출해 직접 닫아줘야 하는 자원이 많다.

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

 

자원 닫기(close 메서드)는 client가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어지기도 함.

이런 자원 중 상당수가 안전망으로 finalizer를 활용하고는 있지만 finalizer는 그리 믿을만 하지 못하다.(Item 8)

 

전통적으로 자원이 제대로 닫힘을 보장하는 수단으로 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 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에서도 예외가 발생할 수 있다는 것이다.

첫 번째 예시에서, readLine()에서 exception 발생하고, close()에서 exception이 다시 발생할 수 있다는 의미이다.

이 때, 스택 추적 내역에 첫 번째로 발생한 exception에 대한 정보가 남지 않아 실제 디버깅을 어렵게 한다.

 

 

이러한 문제들은 Java 7의 try-with-resources 덕에 모두 해결되었다.

이 구조를 사용하기 위해 해당 자원이 AutoCloseable 인터페이스를 구현해야 한다.

AutoCloseable 인터페이스는 void를 반환하는 close 메서드 하나만 정의된 인터페이스이다.

우리가 실제 구현을 진행할 때도 close해야하는 자원을 뜻하는 클래스를 작성한다면 AutoCloseable을 반드시 구현해야 한다.

 

위의 첫 번째 예시코드를 try-finally 에서 try-with-resources로 변경한 코드.

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

 

 

위의 두 번째 예시코드를 try-finally 에서 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);
    }
}

 

try-with-resources로 변경 후에도 catch를 통해서 expcetion을 잡을 수 있음.

728x90
반응형