티스토리 뷰

규칙9. try-finally보다는 try-with-resources를 사용하라


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

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

     

finalizer의 문제


  • 전통적으로 자원이 제대로 닫힘을 보장하는 수단으로 try-finally가 쓰였다.

    static String firstLineOfFile(String path) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(path));
        try {
            return br.readLine();
        } finally {
            br.close();
        }
    }
    • 기기에 물리적인 문제가 생긴다면 firstLineOfFile 메서드 안의 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의 등장


  • 자바7이 투척한 try-with-resources 덕에 위 문제는 모두 해결되었다.

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

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

    • 만약 닫아야 하는 자원을 뜻하는 클래스를 직접 작성하고자 하는 경우 AutoCloseable을 반드시 구현할 것
  • try-with-resources 사용 예제

static String firstLineOfFile(String path) throws IOException {
  try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
  }
}
  • 자원이 둘 이상인 경우 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버전이 짧고 읽기 수월할 뿐 아니라 문제를 진단하기도 휠씬 좋다.

    • firstLineOfFile 메서드에서 readLine, close 호출 양쪽에서 예외가 발생하면, close에서 발생한 예ㅒ외는 숨겨지고 readLine에서 발생한 예외가 기록됨
    • 실전에서는 프로그래머에게 보여줄 예외 하나만 보존되고 여러 개의 다른 예외가 숨겨질 수 있음
      • 이렇게 숨겨진 예외는 스택 추적 내역에 '숨겨졌다(suppressed)'는 꼬리표를 달고 출력됨
      • 자바 7에서 Throwable에 추가된 getSuppressed메서드를 이용하면 코드에서 가져올 수도 있음
  • try-with-resources에서도 catch 절을 쓸수 있다.

    • catch절 덕분에 try문을 더 중첩하지 않고도 다수의 예외를 처리할 수 있음

 

결론


  • 꼭 회수해야 하는 자원을 다룰 때는 try-final 말고, try-with-resources를 사용하자.

    • 코드는 더 짧고 분명해지고, 만들어지는 예외 정보도 훨씬 유용함
  • try-with-resources 로는 정확하고 쉽게 자원을 회수할 수 있다.

     


끝으로

이 글이 도움이 되었다면, Google 광고 한번씩 클릭 부탁 드립니다. 🙏🙏🙏

광고 클릭은 많은 힘이 됩니다!

반응형
댓글