Java의 try-with-resources는 선언한 자원을 초기화한 순서와 반대로 닫습니다. 두 자원 A와 B를 이 순서로 선언하면 본문이 끝난 뒤 B를 닫고 다음 A를 닫습니다. 본문에서 예외가 발생해도 자원 정리를 진행합니다.
본문 예외가 주 예외로 남고 close에서도 예외가 나면 정리 중 생긴 예외는 suppressed 예외로 연결될 수 있습니다. 본문·종료 순서·예외 종류를 각각 기록해야 합니다.
선언 순서대로 열고 역순으로 닫습니다
try-with-resources의 자원은 선언될 때 왼쪽에서 오른쪽 순서로 초기화됩니다. 블록을 벗어날 때는 그 반대로 닫습니다. 따라서 A를 먼저 선언하고 B를 나중에 선언하면 B의 close()가 먼저 실행된 뒤 A의 close()가 실행됩니다. 이는 중첩된 자원에서 안쪽 자원을 먼저 정리하는 흐름과 맞닿아 있습니다. 추적 문제에서는 선언을 한 줄씩 기록한 다음, 종료 단계에서 목록을 뒤집어 보는 것이 간단합니다.
본문 예외가 발생해도 두 자원을 닫습니다
try (Resource a = open("A");
Resource b = open("B")) {
log("body");
throw new WorkException();
}| 순서 | 행동 | 예외 역할 |
|---|---|---|
| 1 | A 초기화 | 없음 |
| 2 | B 초기화 | 없음 |
| 3 | 본문 실행 후 WorkException 발생 | 주 예외 후보 |
| 4 | B.close() | 여기서 난 예외는 suppressed 예외로 남을 수 있음 |
| 5 | A.close() | 여기서 난 예외도 suppressed 예외로 남을 수 있음 |
본문에서 예외가 없고 B와 A의 close도 정상이라면 정리는 B, A 순서로 끝납니다. 본문에서 WorkException이 발생하고 두 close도 각각 예외를 던진다면, 본문 예외가 호출자에게 전달되는 주 예외가 되고 close에서 발생한 예외들은 suppressed 예외로 보관됩니다. Throwable.getSuppressed()로 그 예외를 확인할 수 있습니다. 반대로 본문은 정상인데 close에서 예외가 나면, 자원 종료 중 먼저 전달되는 close 예외와 나머지 예외의 관계를 구체 코드로 따로 추적해야 합니다.
예외를 하나로 뭉개지 말고 순서대로 분류합니다
- 자원 선언과 초기화 순서를 적습니다.
- 본문의 정상 완료 또는 발생 예외를 적습니다.
- close 순서를 선언 순서의 역순으로 정합니다.
- 본문과 각 close가 던지는 예외를 주 예외와 suppressed 예외로 분리합니다.
- 필요하면 AutoCloseable.close가 선언한 예외 허용 범위를 확인합니다.
close가 먼저 선언한 순서로 실행된다고 착각하지 않습니다
자원을 A, B 순으로 적었다고 close도 A, B 순서일 것이라고 외우면 역순 정리 문제를 틀립니다. 또 close()에서 발생한 예외가 모두 사라진다고 생각하면 진단 정보를 놓칩니다. 본문 예외가 이미 존재하면 close 예외는 suppressed로 남을 수 있습니다. 실제로는 여러 자원 초기화가 실패하거나 특정 자원이 null인 경우도 있으므로, 이번 예제의 단순한 두 자원 흐름을 모든 경우의 완전한 예외 우선순위표로 오해하지 마세요.
뒤 자원 초기화가 실패해도 먼저 성공적으로 초기화된 자원은 정리 대상이 될 수 있습니다. 예를 들어 A를 만든 뒤 B 생성 과정에서 예외가 발생하면 A의 close가 실행되고, 정리 중 예외가 나면 원래 실패와 함께 보존될 수 있습니다. 이 흐름은 자원 누수를 막는 중첩 try-finally 규칙과 연결됩니다. 하지만 어떤 자원이 생성되었는지, 본문이 실행되었는지, 각 close가 예외를 던졌는지를 확인하지 않고 모든 예외를 같은 순서로 나열하면 오답입니다. 먼저 생성 성공 여부를 표시하고, 살아 있는 자원을 역순으로 정리하세요.
정답을 가리고 확인해 보세요
이 글을 위해 만든 학습 예시이며 공식 기출문제나 판매 카드의 인용이 아닙니다.
A, B 순서로 선언한 자원의 close 순서와 본문 예외가 있을 때 close 예외의 위치를 설명하세요.
정답과 해설 확인
B를 먼저 닫고 A를 닫습니다. 본문 예외가 주 예외로 유지되며 close 예외는 suppressed 예외로 연결될 수 있습니다.Java SE 21 JLS try-with-resources 규칙과 AutoCloseable 계약을 적용합니다. 예제의 예외 흐름은 본문 예외가 발생한 경우로 한정합니다.