[Effective Java]Item9. try-finally보다는 try-with-resources를 사용하라

최강일·2024년 4월 6일
0

Effective Java

목록 보기
8/9

java lib에는 close메서드를 호출해 직접 닫아줘야 하는 자원이 많다.
예로 InputStream,OutputStream,java.sql.Connection 등등이 있다.

자원 닫기는 클라이언트가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어지기도 한다.
이런 자원 중 상당수가 안전망으로 finalizer를 활용하고는 있지만 finalizer는 그리 믿을만하지 못하다.

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

try-finally는 더 이상 자원을 회수하는 최선의 방책이 아니다.

public class TopLine {

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

    }

나쁘지 않지만, 자원을 하나 더 사용한다면?

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

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

위 방법은 2가지 단점이 존재한다.

  1. 문제는 안되지만 순식간에 코드가 난잡해지고 가독성도 떨어진다.
  2. 세밀한 예외처리가 불가능하다.

만약 try문과 finally문 둘 다에서 예외가 발생할 경우, 두번째 예외가 첫번째 예외를 집어삼키게 된다는 결점이 있다.
이러면 디버깅 자체가 난항을 겪게된다.

try-with-resources : 자원을 회수하는 최선책!

위의 try-finally 문제를 해결한 것이 바로 java7에서 등장한 try-with-resources다.

public class TopLine {

    static String firstLineOfFile(String path) throws IOException {
        try (BufferedReader br = new BufferedReader(
                new FileReader(path))) {
            return br.readLine();
        }
    }
    public static void main(String[] args) throws IOException {
        String path = args[0];
        System.out.println(firstLineOfFile(path));
    }
}

바로 try 안에 파라미터로 자원을 넘겨주는 방식이다.
자원이 한개라 크게 와닿지 않아 추가 예제를 살펴본다.

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

    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);
        }
    }
    public static void main(String[] args) throws IOException {
        String src = args[0];
        String dst = args[1];
        copy(src, dst);
    }
}

자원이 몇개던 간단하게 작성이 가능하다.

try-with-resources에서도 catch문을 사용 가능하다.

public class TopLineWithDefault {

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

정리

꼭 회수해야 하는 자원을 다룰 때는 try-with-resources를 쓰자.
예외는 없다. 코드는 더 짧고 분명해진다.
만들어지는 예외 정보도 훨씬 유용하다.

profile
Search & Backend Engineer

0개의 댓글