Java/이펙티브 자바

아이템9. try-finally 보다 try-with-resources 를 사용하라.

PHM 2023. 6. 7. 10:17

핵심정리

- try-finally 는 더이상 최선의 방법이 아니다. (자바7부터)

- try-with-resources를 사용하면 코드가 더 짧고 분명하다.

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

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

 

문제 1. try-finally

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 {
        in.close(); // 여기서 에러
        out.close();
    }
}

- out.close가 실행이 안될 수 도 있다.

 

문제 2. try-finally

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

- 코드에는 문제가 없지만, 코드가 너무 지저분하다.

 

문제 3. try-finally

public class TopLine {
    // 코드 9-1 try-finally - 더 이상 자원을 회수하는 최선의 방책이 아니다! (47쪽)
    static String firstLineOfFile(String path) throws IOException {
        BadBufferedReader br = new BadBufferedReader(new FileReader(path));
        try {
            return br.readLine();   // CharConversionException
        } finally {
            br.close();             // StreamCorruptedException
        }
    }

    public static void main(String[] args) throws IOException {
        System.out.println(firstLineOfFile("pom.xml"));     // 가장 나중에 발생한 예외인 StreamCorruptedException 가 보인다.
    }
}

- 가장 처음의 발생한 예외를 알 수 없다.

- try-with-resources 를 사용한다면 두 가지 예외 순서대로 다 보인다.

 

 

해결 방안1. try-with-resources

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

- catch 문이나 finally 문도 사용 가능하다.

 

완벽공략

- p48, 자바 퍼즐러 예외 처리 코드의 실수

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) {   // IOException 이 아니라 런타임ex이 터진다면 catch 문 X
            // TODO 안전한가?
        }

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

    }
}

 

- p49, try-with-resources 바이트코드

    ㆍ중첩된 try-catch 문을 사용

    ㆍaddSuppressed 함수로 에러를 순서대로 담아줘서 출력 ( 첫번째 에러 보존 )

    ㆍclose 함수를 여러번 호출 - idempotent