[Effective-Java] Item9 - try-finally보다는 try-with-resources를 사용하라

imcool2551·2022년 4월 2일
0

Effective-Java

목록 보기
8/8
post-thumbnail

1. close 메서드


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

  • InputStream, OutputStream
  • java.sql.Connection

close 메서드가 호출되지 않으면 이는 성능 문제로 이어질 수 있다. 전통적으로 close 메서드는 try-finally 의 finally 절에서 직접 호출해줬는데 이는 다양한 문제가 발생할 수 있다.

2. try-finally의 문제점


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

자원을 하나만 사용하는 경우 코드 자체는 별로 복잡해 보이지 않는다. 그런나 이 경우에도 미묘한 문제가 발생할 수 있다.

파일을 읽어들이는 기기 자체에 문제가 생긴다면 br.readLine()이 실패하여 예외가 발생할 것이고 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 문 때문에 코드가 복잡해져서 의도가 한 눈에 들어오지 않는다. 마찬가지로, 예외가 삼켜지는 상황이 발생할 수 있다.

3. try-with-resources


try-finally의 문제점들은 자바7에서 등장한 try-with-resources 문을 사용하면 깔끔하게 해결된다.

이 문법을 사용하려면 사용하는 자원이 Autoclosable 인터페이스를 구현해야 한다. 이 인터페이스는 반환값이 없는 close 메서드 하나만 정의한 매우 간단한 인터페이스다. 이미 많은 자바 라이브러리, 서드파티 라이브러리들이 이 인터페이스를 구현했다.

만약 닫아야 하는 자원을 사용하는 클래스를 작성한다면 꼭 Autoclosable을 구현하도록 하자.

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

간단하고 의도도 명확하다. close()는 보이지 않지만 자동으로 호출된다.

예외가 삼켜지는 문제가 해결된다. 기기에 문제가 발생하여 파일을 읽어들이는 부분(readLine/read)과 파일을 종료하는 부분(close)에서 동시에 예외가 발생해도 먼저 발생한 예외가 기록된다. 그 외의 예외들은 버려지지 않고 스택 추적내에 숨겨졌다는 suppressed 꼬리표를 달고 출력 된다. 필요하다면, 자바7에서 추가된 ThrowablegetSuppressed 메서드를 통해 프로그램 코드로 가져올 수도 있다.

4. 결론


닫아줘야 하는 자원이 있다면 try-finally 대신 try-with-resources를 사용하도록 하자. 다음과 같은 장점이 있다.

  • 코드가 더 짧아지면서 의도가 명확해진다.

  • 만들어지는 예외 정보가 훨씬 유용하다.

  • 실수로 자원을 회수하지 않아 발생할 수 있는 성능문제가 발생하지 않는다.

profile
아임쿨

0개의 댓글