자바 언어·플랫폼 용어 사전
예외·자원AutoCloseable · 자원 누수 · suppressed

try-with-resources

close()를 컴파일러가 대신 넣어 주는 문법. finally 수동 정리의 함정을 없앤다.

AutoCloseable을 구현한 자원을 선언하면 컴파일러가 close() 호출을 대신 넣어 준다.

try (var conn = ds.getConnection();
     var ps = conn.prepareStatement(SQL);
     var rs = ps.executeQuery()) {
    while (rs.next()) { ... }
}   // rs → ps → conn 순서로 자동 close

수동 finally 가 왜 위험한가

InputStream in = null;
OutputStream out = null;
try {
    in = ...; out = ...;
    copy(in, out);
} finally {
    if (in != null) in.close();    // ← 여기서 예외가 나면
    if (out != null) out.close();  // ← 이 줄이 실행되지 않는다 → 누수
}

올바르게 쓰려면 중첩 try 를 또 써야 한다 자원이 셋이면 코드가 손댈 수 없이 커진다

  • 실무에서 가장 흔한 자원 누수 원인이 바로 이 형태였다

억제된 예외(suppressed)

body 에서 예외 A, close() 에서 예외 B 가 나면?

  • 수동 finally — B 가 A 를 덮어써 원인이 사라진다 (최악)

  • try-with-resources — A 를 던지고 B 를 A.getSuppressed() 에 담는다

  • "진짜 원인" 이 보존된다. 스택트레이스에 Suppressed: 로 찍힌다

닫는 순서와 effectively final

선언의 역순으로 닫는다 — 나중에 연 것(의존하는 쪽)부터

  • ResultSet → Statement → Connection

Java 9 부터는 밖에서 만든 변수도 쓸 수 있다

  • 단, effectively final 이어야 한다
  • try (existingResource) { ... }

실무 주의점

  • Stream 도 AutoCloseable 이다. 파일 기반(Files.lines) 은 반드시 닫아야 한다
    • 컬렉션 기반 스트림은 닫을 필요가 없어 습관이 안 든다 → 파일에서 FD 누수
  • 커넥션 풀에서 close() 는 '반납' 이다. 안 닫으면 풀이 마르고 전체가 멈춘다
  • close() 가 조용히 실패하는 구현은 피한다 — 삼켜진 실패는 추적이 불가능하다

컴파일러가 실제로 만드는 코드

// 우리가 쓴 것
try (var a = open()) { use(a); }

// javac 가 펼친 것 (개념적으로)
var a = open();
Throwable primary = null;
try {
    use(a);
} catch (Throwable t) {
    primary = t;  throw t;
} finally {
    if (a != null) {
        if (primary != null) {
            try { a.close(); }
            catch (Throwable sup) { primary.addSuppressed(sup); }  // 원인 보존
        } else {
            a.close();
        }
    }
}

손으로 매번 이렇게 쓰는 것은 현실적이지 않다 — 그래서 문법으로 올렸다.

close() 는 멱등해야 한다

같은 자원을 두 번 닫는 상황은 실제로 자주 생긴다

  • 중첩 try 에서 안팎이 모두 닫는다
  • 프레임워크와 애플리케이션이 각자 닫는다

AutoCloseable 규약은 멱등을 '권장' 하고, Closeable(java.io) 은 멱등을 '요구' 한다 직접 구현할 때는 닫힘 플래그를 두는 편이 안전하다

면접 함정

  • "finally에서 닫으면 같다" → close 중 예외에서 원인이 소실되고 뒷 자원이 누수된다.
  • "모든 Stream을 닫아야 한다" → 파일·소켓 기반만 필요하다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 컬렉션·예외·리소스