본문은 성공했지만 두 자원의 close가 모두 실패했습니다. 대표 예외와 suppressed 순서는 무엇인가요?
잠깐, 답변을 보기 전에
먼저 내 말로 설명해 볼까요?
답변과 점검 포인트 펼치기답변 접기
구두 답변
정의를 외우기보다, 원리와 조건을 연결해 설명해 보세요.
본문이 정상적으로 완료되면 close 단계의 첫 실패가 primary가 됩니다. r1을 먼저 선언하고 r2를 나중에 선언하면 close 호출 순서는 r2.close() → r1.close()이므로, 둘 다 실패하는 일반적인 경우 close r2 예외가 호출자에게 전달되고 close r1 예외가 primary.getSuppressed()[0]이 됩니다.
try (var r1 = new FailingResource("r1");
var r2 = new FailingResource("r2")) {
// 본문 성공
} catch (Exception e) {
// primary: close r2
// suppressed[0]: close r1
}
이 결과는 선언 순서가 아니라 실제 역순 close와 첫 실패 선택을 따른 것입니다. 한 close가 실패해도 이미 성공적으로 생성된 다른 자원의 close를 계속 시도하므로 두 번째 실패를 suppressed로 보존합니다. 다만 일반적인 서로 다른 예외 인스턴스이며 suppression이 허용된다는 전제가 있습니다. Throwable이 suppression을 비활성화했거나 primary와 같은 인스턴스를 다시 추가하면 suppressed 배열이 기대와 달라지거나 self-suppression의 IllegalArgumentException이 발생할 수 있습니다.
따라서 테스트는 예외 메시지를 close r1, close r2로 고정하여 primary 타입·메시지, suppressed 길이·순서를 확인해야 합니다. 운영에서는 suppressed까지 내부 관측에 남기되, try-with-resources가 외부 DB 변경을 rollback하거나 자원 API의 이중 close 정책을 대신 결정하지는 않는다는 한계를 분리해 기록하겠습니다.
득점 포인트
이해가 드러나는 지점을 확인해 보세요.
- 본문 성공 후 역순 close에서
r2실패가 primary이고r1실패가 suppressed가 되는 중간 호출 순서를 정확히 제시합니다. - suppression 비활성화와 self-suppression 예외를 일반 경로의 조건부 한계로 덧붙여 “항상 배열에 저장”이라는 과장을 피합니다.
감점 포인트
놓치기 쉬운 조건과 오해를 짚어 보세요.
- 첫 선언 자원인
r1이 항상 대표 예외가 된다고 말하면 안 됩니다. - close 실패 하나가 발생하면 나머지 자원 close가 무조건 생략된다고 설명하면 안 됩니다.
더 파고들 거리
하나 더 질문하며 이해의 범위를 넓혀 보세요.
- 예외 인스턴스를 서로 다르게 생성한 경우와 같은 인스턴스를 재사용한 경우
getSuppressed()결과가 어떻게 달라지는지 API 테스트로 확인해 보세요. - suppressed stack trace를 내부 로그에는 보존하면서 외부 오류에는 안전한 요약만 내보내는 관측 정책을 설계해 보세요.
득점·감점 포인트는 학습용 자기 점검 기준이며, 특정 회사의 실제 채점표가 아닙니다.