• Home
  • About
    • Ara Jo photo

      Ara Jo

      Aspiring Backend Developer :)

    • Learn More
    • Email
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

Book/Effective Java 3E/Item9. try-finally보다는 try-with-resources를 사용하라

15 Dec 2021

Reading time ~2 minutes

자바 라이브러리에는 InputStream, OutputStream, java.sql.Connection 과 같은 close 메서드를 호출해 직접 닫아줘야 하는 자원이 많다. 자원 닫기는 클라이언트가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어지기도 한다. 자원을 닫는 두 가지 방법 try-finally와 try-with-resources를 비교해보자.

try-finally

전통적으로 자원을 닫는 방법으로 try-finally를 사용해왔다. 예외가 발생하거나 메서드에서 반환되는 경우를 포함해서 말이다.

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

이 코드에서 만약, 자원이 둘 이상이라면 어떻게 될까?

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를 하던 중 예외가 발생하더라도 close 메서드를 호출할 때 예외가 발생하면 두 번째 예외만 남기 때문에 디버깅을 몹시 어려워진다.

try-with-resources

try-finally가 가지는 문제들을 자바 7부터 제공하는 try-with-resources에서 모두 해결해주었다. (이 구조를 사용하려면 해당 자원이 AutoCloseable 인터페이스를 구현해야 한다.)

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

이 코드는 위의 코드를 try-with-resources를 활용해서 다시 작성한 코드이다. 이 방법의 코드가 훨씬 짧고 읽기 쉬울뿐 아니라 문제를 진단하기에도 훨씬 좋다. 아까와 마찬가지로 두 가지 예외가 발생한다면 close에서 발생한 두 번째 예외는 숨겨지고 첫 번째 예외가 기록된다.

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

try-finally와 마찬가지로 try-with-resources에서도 catch 절을 쓸 수 있다. catch 절 덕분에 try 문을 중첩하지 않고도 다수의 예외를 처리할 수 있다. 위의 코드는 파일을 열거나 데이터를 읽지 못했을 때 예외를 던지는 대신 기본값을 반환하도록 예외처리를 해준 코드이다.

꼭 회수해야 하는 자원을 다룰 때는 try-finally 대신, try-with-resources를 사용하자. 코드가 더 짧고 분명해질뿐 아니라, 만들어지는 예외 정보도 훨씬 유용하다. 무엇보다도, try-with-resources는 정확하고 쉽게 자원을 회수할 수 있다.



bookeffective_javajava Share Tweet +1