본문 바로가기
개발 공부/Java

이펙티브 자바 아이템 9 - try-finally 보다 try-with-resouces 를 사용하라 - 완벽 공략

by 개발인생 2022. 10. 14.
반응형

아이템 9 - try-finally 보다 try-with-resouces 를 사용하라 - 완벽 공략

이 글은 백기선 님의 이펙티브 자바 강의와 이펙티브 자바 3 / E 편을 참고하여 작성하였습니다.

finally 블럭에서 try - catch 로 다시 감싸져있다면 어떻게 될까?

public class Copy {
   private static final int BUFFER_SIZE = 8 * 1024;

   // 코드 9-2 자원이 둘 이상이면 try-finally 방식은 너무 지저분하다! (47쪽)
   static void copy(String src, String dst) throws IOException {
      InputStream in = new FileInputStream(src);
      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 {
         try {
            out.close();
         } catch (IOException e) {
            // TODO 이렇게 하면 되는거 아닌가?
         }

         try {
            in.close();
         } catch (IOException e) {
            // TODO 안전한가?
         }
      }
   }

   public static void main(String[] args) throws IOException {
      String src = args[0];
      String dst = args[1];
      copy(src, dst);
   }
}

겉으로 봤을 때는 안전해 보이지만 안전하지 않다.

위의 코드는 IOException 을 잡고있지만 IOException 이 아닌 다른 오류가 발생한다면

뒤의 코드는 실행되지 않는다.

public class Copy {
   private static final int BUFFER_SIZE = 8 * 1024;

   // 코드 9-2 자원이 둘 이상이면 try-finally 방식은 너무 지저분하다! (47쪽)
   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();
      }
   }

   public static void main(String[] args) throws IOException {
      String src = args[0];
      String dst = args[1];
      copy(src, dst);
   }
}

finally 블럭에서 try - catch 로 다시 감싸는 것 보다는 위의 코드가 훨씬 안전하다.

try-with-resources 사용하면 훨씬 간결하게 문제를 해결할 수 있다.


try-with-resources 바이트코드

public class TopLine {
   public TopLine() {
   }

   static String firstLineOfFile(String path) throws IOException {
      BufferedReader br = new BufferedReader(new FileReader(path));

      String var2;
      try {
         var2 = br.readLine();
      } catch (Throwable var5) {
         try {
            br.close();
         } catch (Throwable var4) {
            var5.addSuppressed(var4);
         }

         throw var5;
      }

      br.close();
      return var2;
   }

   public static void main(String[] args) throws IOException {
      String path = args[0];
      System.out.println(firstLineOfFile(path));
   }
}

try-with-resources 코드가 컴파일러에서 빌드 된 뒤의 클래스 파일이다.

try {
         var2 = br.readLine();
      } catch (Throwable var5) {
         try {
            br.close();
         } catch (Throwable var4) {
            var5.addSuppressed(var4);
         }

         throw var5;
      }

만약 코드 실행 중 예외가 발생했을 때 첫번째 예외를 throw 하지만

후속으로 발생한 예외가 있다면 addSuppressed 를 호출해 후속으로 발생한 에러를 담아준다.

컴파일러된 코드를 보면 close() 메서드가 여러번 호출되고 있다.

그래서 close() 를 구현할 때는 멱등성을 가져야 한다.

반응형

댓글