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

신민철·2023년 4월 14일
2

Effective Java

목록 보기
9/23
post-thumbnail

자바 라이브러리 중에는 close로 닫아줘야 하는 자원들이 많은데 InputStream, java.sql.Connection 등이 그 예다.

item8에서 close의 안전망으로 finalizer를 사용하는 경우도 있다고 했지만 사실상 사용하면 안된다.

그래서 전통적으로는 try-finally가 쓰였다.

static String firstLineOfFile(String path) throws 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();
		}
	}
}

지금 자원이 2개인데도 순식간에 이렇게 코드가 지저분해졌다!

지저분해지는 것뿐 아니라 예외 상황에서도 단점이 있다. Exception은 try 부분과 finally 부분 둘 다에서 터질 수 있다. 이런 상황에서는 한 예외가 다른 예외를 집어 삼켜서 하나의 예외만 터진 것처럼 보일 수 있다.

물론 어떤 예외가 나올지는 코드 수정을 통해 바꿀 수는 있지만 똑같이 집어삼킬 것이다.



대신 try-with-resources라는 대안이 있다!

이 구조에서는 AutoClosable 인터페이스를 구현해야 한다. 단순히 void형 비어있는 close() 메소드만 정의한 인터페이스다.

static String firstLineOfFile(String path) throws IOException {
	try (BufferedReader br = new BufferedReader(
					new FileReader(path))) {
		return br.readline();
	}
}
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);
	}
}

딱 보기만 해도 굉장히 간결하고 어떤 문제가 터졌는지 진단하기도 매우 좋다!

첫번째 케이스에서 close() 메소드가 안보이는데 readLine과 둘 다에서 예외가 발생하면 close에서 발생한 예외는 숨겨지고 readLine은 보여지게 되는데 숨겨진 것들을 보고 싶으면 스택 추적 내역에서 확인할 수 있다!

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

try-with-resources에서도 catch 절을 사용할 수 있는데 try문의 중첩 없이 다수의 예외를 처리할 수 있게 된다.

핵심 정리
꼭 회수해야 하는 자원을 다룰 때는 try-with-resources를 사용하자! 코드는 간결해지고 Exception 처리 면에서도 우수하다. 또한 자원도 확실하게 회수할 수 있다.

0개의 댓글