[Java] try-catch 정확히 알고 쓰자

HenryHong·2026년 1월 8일

java

목록 보기
5/15
post-thumbnail

1. 세 가지 문법, 역할부터 구분하기

자바에서 예외 처리 관련해서 자주 보는 문법은 크게 세 가지다.

  • try-catch
  • try-finally
  • try-with-resources

이 셋은 서로 대체 관계라기보다는, 역할이 조금씩 다른 도구 세트라고 이해하는 게 좋다.


2. try-catch: 예외를 “잡아서 처리”하는 기본 문법

try-catch의 목적은 예외를 잡아서 처리/전환/로그하는 것이다.

try {
    doBusiness(); // 여기서 예외 발생 가능
} catch (IOException e) {
    // 예외 처리 (로그, 사용자 메시지, 래핑 등)
    log.error("I/O 실패", e);
    throw new CustomException(e);
}

특징:

  • 예외를 잡아서:
    • 로그를 남기거나,
    • 사용자 친화적인 예외로 바꾸거나,
    • 일부만 복구하고 다시 진행할 수 있다.
  • 자원 해제는 자동이 아니다.
    • 닫아야 할 자원(스트림, 소켓 등)이 있으면 별도로 close()를 호출해야 한다.

즉, try-catch“예외를 어떻게 다룰 것인가”에 집중된 문법이다.


3. try-finally: “무슨 일이 있어도 마지막에 정리”할 때

try-finally의 역할은 예외가 나든 말든, 마지막에 반드시 실행해야 하는 정리 작업을 넣는 것이다.

Lock lock = lock();
try {
    // 동시성 민감한 비즈니스 로직
    doCriticalWork();
} finally {
    lock.unlock(); // 예외가 나도 무조건 호출
}

또는 자원 해제:

InputStream in = null;
try {
    in = new FileInputStream("data.txt");
    readData(in);
} finally {
    if (in != null) {
        in.close(); // 여기서 예외가 나면, 원래 예외를 덮어버릴 수 있음
    }
}

특징:

  • finally 블록은:
    • 예외가 터져도,
    • 중간에 return 해도,
    • 거의 항상 실행된다.
  • 그래서 unlock(), close(), release() 같은 정리/해제 작업을 넣을 때 많이 사용한다.
  • 단점:
    • 자원 해제를 직접 관리해야 해서 코드가 장황해진다.
    • 비즈니스 로직과 close() 양쪽에서 예외가 나면,
      finally 쪽 예외가 원래 예외를 덮어 버릴 수 있다.

그래서 요즘은 “자원 해제” 용도로 try-finally를 새로 쓰는 경우는 거의 없고,
락/트랜잭션 경계 같은 곳에 제한적으로 쓰는 편이다.


4. try-with-resources: 자원 자동 해제 + 예외 정보까지 안전하게

try-with-resources는 Java 7에서 도입된 문법으로,
닫아야 할 자원(AutoCloseable) 을 안전하고 간결하게 처리하기 위한 특화된 형태다.

try (FileInputStream in = new FileInputStream("data.txt")) {
    readData(in); // 여기서 예외 A 발생 가능
}

동작:

  • try (...) 괄호 안에 선언한 자원은 try 블록이 끝날 때 자동으로 close() 호출된다.
  • 비즈니스 로직에서 예외 A가 터지고, close() 과정에서 예외 B가 또 터져도:
    • A가 “주 예외”로 유지되고,
    • B는 A.getSuppressed()Suppressed 예외로 붙는다.

예시:

try (MyResource r = new MyResource()) {
    r.doWork();           // 예외 A
} catch (Exception e) {
    // e == A (비즈니스 예외)
    for (Throwable sup : e.getSuppressed()) {
        // 여기에 close() 중 발생한 예외 B들이 들어있음
    }
}

왜 “더 안전”하냐면:

  • try-finally에선 finally에서 난 예외가 원래 비즈니스 예외를 덮어서 로그/디버깅이 힘들어졌는데,
  • try-with-resources는 원래 예외를 살리고, 닫기 중 예외는 Suppressed 목록으로만 보내서 중요한 정보(비즈니스 실패 원인)를 잃지 않도록 만들어줬기 때문.

추가로:

  • 자원 여러 개도 자연스럽게 처리 가능.

    try (Connection conn = dataSource.getConnection();
         PreparedStatement ps = conn.prepareStatement(sql);
         ResultSet rs = ps.executeQuery()) {
    
        // JDBC 로직...
    
    } // 여기서 rs → ps → conn 순서로 자동 close
  • 코드가 짧고, 실수할 여지가 훨씬 적다.


5. 실무에서는 뭘 어떻게 쓰나?

실무 기준으로 정리하면 이렇게 쓸 수 있다.

  • 예외 처리만 필요하고, 특별히 닫을 자원이 없다. or
    락/트랜잭션처럼, “어쨌든 반드시 실행해야 할 마지막 동작”이 있다.
    • try-catch / try-catch-finally
  • 스트림, 파일, 소켓, DB 커넥션, Reader/Writer 등 AutoCloseable 자원이 있다.
    • 무조건 try-with-resources 우선
      (Effective Java, 공식 튜토리얼 모두 이 방향을 강하게 권장).

한 줄로 요약하면:

  • try-catch는 예외를 “어떻게 처리할지”에 대한 구조,
  • try-finally는 “예외와 상관없이 마지막에 반드시 실행할 작업”을 위한 구조,
  • try-with-resources는 AutoCloseable 자원을 자동으로 안전하게 닫고,
    비즈니스 예외와 close 예외가 동시에 터져도 중요한 쪽(비즈니스 예외)을 보존해 주는 현대식 패턴이다.

[참조]
https://mungto.tistory.com/526
https://www.baeldung.com/java-try-with-resources
https://velog.io/@ntigo/%EC%95%84%EC%9D%B4%ED%85%9C-9.-try-finally-%EB%B3%B4%EB%8B%A4-try-with-resources%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%9D%BC
https://www.linkedin.com/posts/moresh-shende_java-exceptionhandling-bestpractices-activity-7308522684223565824-GsBR

profile
주니어 백엔드 개발자

0개의 댓글