본문 바로가기
language/java

Java try-catch-finally 흐름 완벽 이해하기

by 죄니안죄니 2026. 5. 29.
반응형

Java try-catch-finally 흐름 완벽 이해하기

Java 예외 처리에서 가장 기본이면서도,
실무에서는 의외로 많은 개발자가 정확히 이해하지 못하는 것이 바로:

try-catch-finally 흐름

입니다.

특히:

  • finally는 언제 실행되는가?
  • return과 finally 충돌 시?
  • 예외 재전파는 어떻게 되는가?
  • JVM은 예외를 어떻게 처리하는가?
  • suppressed exception은 무엇인가?

같은 부분은 실무 디버깅에서 매우 중요합니다.

이번 글에서는:

  • try-catch-finally 실행 흐름
  • Stack Unwinding
  • finally 실행 보장
  • return 충돌
  • throw 충돌
  • suppressed exception
  • 실무 예외 처리 패턴

까지 깊게 정리해보겠습니다.


1. try-catch-finally란?

Java 예외 처리 기본 구조.


2. 기본 형태

 
try {

} catch(Exception e) {

} finally {

}
 

3. 역할


블록 역할
try 예외 발생 가능 코드
catch 예외 처리
finally 무조건 실행할 코드

4. 가장 기본 흐름

 
try {

    System.out.println("A");

} catch(Exception e) {

    System.out.println("B");

} finally {

    System.out.println("C");
}
 

5. 예외 없으면?

실행 순서:

A
C
 

6. 예외 발생하면?

 
try {

    throw new RuntimeException();

} catch(Exception e) {

    System.out.println("catch");

} finally {

    System.out.println("finally");
}
 

7. 실행 결과

catch
finally
 

8. finally 핵심 특징

매우 중요합니다.

finally는 거의 항상 실행된다
 

입니다.


9. 왜 finally가 중요할까?

대표 목적:

  • 파일 close
  • DB connection 반환
  • lock 해제
  • 리소스 정리

10. 예시

 
finally {

    connection.close();
}
 

11. JVM 내부 흐름

매우 중요합니다.

예외 발생 시 JVM은:

Stack Unwinding
 

수행.


12. Stack Unwinding이란?

Stack unwinding 이란:

호출 스택을 되돌아가며 catch를 찾는 과정

입니다.


13. 예시 흐름

main()
 ↓
service()
 ↓
repository()
 ↓
예외 발생
 

repository 종료
↓
finally 실행
↓
service 전달
↓
finally 실행
↓
main 전달
 

14. 매우 중요한 점

예외가 위로 전파되는 과정에서도:

finally는 실행됨
 

입니다.


15. finally가 실행 안 되는 경우

거의 없지만 존재.


16. 대표 예외 상황


상황 finally 실행
System.exit() X
JVM 강제 종료 X
OS 프로세스 kill X
치명적 JVM crash X

17. return과 finally

매우 중요합니다.

실무 면접 단골.


18. 예시

 
public int test() {

    try {

        return 1;

    } finally {

        System.out.println("finally");
    }
}
 

19. 결과

finally 출력 후 return
 

즉:

return 전에 finally 실행
 

됩니다.


20. 왜 그럴까?

JVM이 내부적으로:

return 값 임시 저장
↓
finally 실행
↓
실제 return
 

흐름 수행.


21. 더 위험한 경우

finally 안에 return 존재.


22. 예시

 
public int test() {

    try {

        return 1;

    } finally {

        return 2;
    }
}
 

23. 결과는?

2
 

24. 왜 위험할까?

finally의 return이:

기존 return 덮어씀
 

입니다.


25. 예외도 덮어쓸 수 있음

매우 위험.


26. 예시

 
try {

    throw new RuntimeException();

} finally {

    return;
}
 

27. 결과

예외 사라짐
 

28. 왜 문제일까?

디버깅 지옥 가능.

즉:

실제 오류 숨김
 

발생.


29. 실무 핵심 원칙

매우 중요.

finally 안에서 return 금지
 

입니다.


30. finally 안에서 throw도 위험

예시:

 
try {

    throw new RuntimeException("A");

} finally {

    throw new RuntimeException("B");
}
 

31. 결과

B만 보일 수 있음
 

32. 원래 예외 A는?

사라질 수 있음.

즉:

원인 손실
 

가능.


33. 이것이 try-with-resources 등장 이유 중 하나

매우 중요합니다.


34. try-with-resources

 
try (
    BufferedReader br = ...
) {

}
 

35. 목적

리소스 자동 close
 

입니다.


36. close 중 예외 문제 해결

기존 finally 방식:

원래 예외가 close 예외에 덮임
 

가능.


37. suppressed exception 등장

Suppressed exception 이란:

원래 예외를 보존하면서 추가 예외 기록

하는 기능.


38. 예시 흐름

원래 예외 발생
↓
close() 중 추가 예외
↓
원래 예외 유지
↓
추가 예외 suppressed 저장
 

39. 확인 방법

 
exception.getSuppressed()
 

40. 왜 중요할까?

원인 추적 가능성 증가.


41. catch 순서도 중요

매우 중요합니다.


42. 안 좋은 예

 
catch(Exception e)

catch(IOException e)
 

43. 왜 문제일까?

상위 타입이 먼저 잡음.

즉:

하위 catch unreachable
 

컴파일 오류.


44. 올바른 순서

구체적인 예외
↓
더 큰 범위 예외
 

순.


45. multi-catch

Java 7 이후 가능.


46. 예시

 
catch(IOException | SQLException e)
 

47. finally와 변수 변경

예시:

 
int x = 1;

try {

    return x;

} finally {

    x = 2;
}
 

48. 결과는?

1 반환
 

49. 왜?

return 값은 이미:

임시 저장
 

되었기 때문.


50. 객체는 다를 수 있음

예시:

 
List<String> list =
    new ArrayList<>();

try {

    return list;

} finally {

    list.add("A");
}
 

51. 결과

[A]
 

포함 가능.

왜냐하면:

참조 객체 자체 수정
 

했기 때문.


52. 실무에서 자주 하는 실수

1) finally에서 return

예외 삼켜질 수 있음.


2) catch(Exception) 남용

원인 분석 어려움.


3) 리소스 close 누락

메모리 누수 가능.


4) try-with-resources 안 사용

현대 Java에선 비효율적.


53. 실무 권장 패턴

현대 Java에서는 보통:

 
try-with-resources
 

우선 사용.


54. 이유

  • close 자동 처리
  • suppressed exception 지원
  • 코드 간결
  • 예외 보존 개선

55. 핵심 흐름 요약

예외 발생
↓
Stack Unwinding
↓
finally 실행
↓
catch 탐색
↓
처리 or 전파
 

56. 가장 중요한 핵심 한 줄

finally는 “거의 항상 실행”되지만,
finally 안의 return/throw는 기존 예외 흐름을 깨뜨릴 수 있다
 

입니다.


57. 정리

try-catch-finally는 단순 문법이 아닙니다.

실제로는:

  • JVM Stack Unwinding
  • 예외 전파
  • suppressed exception
  • 리소스 관리
  • return 흐름 제어

전체와 연결되는 Java 핵심 실행 메커니즘입니다.

특히 실무에서는:

  • finally return 금지
  • try-with-resources 사용
  • catch 순서
  • 예외 보존
  • Stack Trace 유지

를 정확히 이해하는 것이 매우 중요합니다.

다음 글에서는:

try-with-resources 원리

를 AutoCloseable, suppressed exception 내부 구조, close 순서, JDBC/IO 실무 패턴까지 포함해서 깊게 정리해보겠습니다.

반응형

댓글