티스토리 뷰

자바 라이브러리에는 InputStream, OutputStream, java.sql.Connection과 같이 자원을 할당받고 회수해야 하는 친구들이 많다.

I/O 작업과 관련 된 녀석들이 그런 것 같다.

 

 

클래스 내부로직에서 Exception이 발생해 close 메소드를 호출하지 못할 수 있다.

따라서 전통적으로 try-finally 블록을 통해 모든 로직의 끝에는 항상 close를 호출하게 구현을 했었다.

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

별 문제가 없어 보인다.

그러나 회수해야할 자원이 여러 개라면 다음과 같은 코드를 작성해야 한다.

// 코드 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();
    }
}

try-finally 블록을 try-finally 블록으로 감싸 구현해야 한다. 더 많다면 중첩된 복잡한 구문이 생성될 것이다.

 

 

또 발생할 수 있는 문제는 Exception이 여러 번 발생할 때 두 번째 발생한 예외가 첫 번째 발생한 예외를 집어삼켜 디버깅을 힘들게 한다.

 

 

 

이를 해결하기 위한 대안이 나왔다. 짜란~ try-with-resources이다.

// 코드 9-3 try-with-resources - 자원을 회수하는 최선책! (48쪽)
static String firstLineOfFile(String path) throws IOException {
    try (BufferedReader br = new BufferedReader(
            new FileReader(path))) {
        return br.readLine();
    }
}
// 코드 9-4 복수의 자원을 처리하는 try-with-resources - 짧고 매혹적이다! (49쪽)
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);
    }
}

이 구조를 사용하기 위해선 클래스가 AutoCloseable을 구현한 상태여야 한다.

 

이전보다 코드가 간결하고 읽기 쉽다.

또한 이전에 발생했던 문제인 예외가 잡아먹히는 문제도 스택을 추적해서 표시해 준다고 한다.

 

 

이에 catch 구문을 적용하여 Exception 처리를 쉽게 할 수 있다.

static String firstLineOfFile(String path, String defaultVal) {
    try (BufferedReader br = new BufferedReader(
            new FileReader(path))) {
        return br.readLine();
    } catch (IOException e) {
        return defaultVal;
    }
}

Exception이 발생했을 때 기본 밸류를 return 하게끔 할 수 있다.

이때 catch 블록을 연달아 쓰게 되면 try 블록을 감싸 구현하지 않고 Exception 처리를 다양하게 할 수 있게 된다.

 

 

 

자원을 회수해야 하는 로직에서 try-finally에게 관용은 없다.

무조건 try-with-resources를 사용하도록 하자.

 

 

코드 - 

https://github.com/WegraLee/effective-java-3e-source-code/tree/master/src/effectivejava/chapter2/item9

 

GitHub - WegraLee/effective-java-3e-source-code: 『이펙티브 자바, 3판』(인사이트, 2018)

『이펙티브 자바, 3판』(인사이트, 2018). Contribute to WegraLee/effective-java-3e-source-code development by creating an account on GitHub.

github.com

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함