티스토리 뷰

728x90
[이펙티브 자바 3/E] 아이템 9 : try-finally 보다는 try-with-resources를 사용하라

 

핵심

close 메서드를 호출해 직접 닫아줘야하는 자원에 "try-with-resources"를 적용해 안전하게 닫아주자!!

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

** 자원을 닫지 않으면 성능 문제로 이어질 수 있다.

 

try-finally (Java7 이전)

변수1 = null;
변수2 = null;
try {
   변수1 = new 자원객체1();
   변수2 = new 자원객체2();
   변수1.작업();
   변수2.작업();
   ...
} finally {
   if (변수1 != null) 변수1.close();
   if (변수2 != null) 변수2.close();
}

✅ 어떤 경우에도 자원을 반납하도록 구현하기위해 fianlly를 사용하게 된다.

 null 여부를 추가로 검사해야한다.

 close 해주는 걸 잊으면 그냥 끝..

디버깅의 어려움을 유발한다. 

 

try-with-resources (Java7 이후)

try (변수1 = new 자원객체1();
     변수2 = new 자원객체2()) {
    ...
}

try-with-resources는 try(...)에서 선언된 객체들에 대해 try가 종료될 때 자동으로 close를 호출하여 자원을 해제해주는 기능을 제공한다.

 

 Java7부터 제공한다.

 이때 해제하려는 자원의 객체에는 AutoCloseable 인터페이스가 구현되어 있어야한다. (아이템8 참고)

 

위의 경우가 아니라면 무조건 try-with-resources를 사용하자!!

 

 짧고 읽기 수월해진다.

 close를 잊을 일이 없다.

 문제를 진단하기 좋아진다.

 디버깅의 어려움을 해소한다. 

 

** IntelliJ에서도 다음과 같이 try-fianlly로 자원을 해제할 경우 경고를 띄우며, try-with-rewources로의 변경을 권장하고 있다.

 

 

디버깅의 어려움을 유발하고 해소한다..?

try-finally (Java7 이전)

예외는 try 블록과 finally 블록 모두에서 발생할 수 있다.

이럴 경우 fianlly 블록에서 발생한 예외만 남게되고 try 블록에서 발생한 예외는 알 수 없게 된다.

 

@Test
void throwExceptionTryFinally() throws IOException {
    FileInputStream is = null;
    BufferedInputStream bis = null;
    try {
        is = new FileInputStream("/Users/ellie/MyData/woowacourse/file.txt");
        bis = new BufferedInputStream(is);
        int data = -1;
        while ((data = bis.read()) != -1) {
            System.out.print((char) data);
        }
        throw new IOException("try에서 에러 발생");
    } finally {
        if (is != null) {
            is.close();
        }
        if (bis != null) {
            bis.close();
        }
        throw new IOException("finally에서 에러 발생");
    }
}

 

try-with-resources (Java7 이후)

try 블록과 close에서 모두 예외가 발생할 수 있지만 try 블록에서 발생한 예외가 기록된다.

이때 close에서 발생한 예외는 숨겨지며, 스택 트레이스에 “Suppressed(숨겨짐)” 키워드로 출력된다.

 

public class CustomResource implements AutoCloseable {

    public void doSomething() {
        System.out.println("Do something...");
    }

    @Override
    public void close() {
        System.out.println("CustomResource.close() is called");
        throw new IllegalArgumentException("close에서 에러 발생");
    }
}
@Test
    void throwExceptionTryWithResources() {
        try (CustomResource cr = new CustomResource()) {
            cr.doSomething();
            throw new IOException("try에서 에러 발생");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 

Ref.

https://devlog-wjdrbs96.tistory.com/116

https://codechacha.com/ko/java-try-with-resources/

 

728x90
댓글
공지사항
최근에 올라온 글