[TIL] Java Exception 예외 처리

YJin·2025년 3월 23일

[내배캠 Spring 6기_TIL]

목록 보기
14/56
post-thumbnail

예외(Exception)

: 프로그램 실행 중 발생할 수 있는 의도하지 않은 상황. 프로그램의 비정상적인 동작 혹은 에러가 발생할 수 있으므로 적절히 처리하거나 회피하는 것이 필요하다.

  • 의도하지 않은 예외 : 프로그램이 의도한 대로 동작하지 않는 경우.
  • 의도적인 예외(throw) : 특정 조건에서 의도적으로 예외를 발생시킴.


Error vs Exception


에러 : 런타임 에 발생하고 주로 시스템 리소스 부족으로 발생한다. 발생 시 복구가 어렵다. ex) OutOfMemoryError

예외 : 프로그램 실행 중 발생할 수 있는 의도하지 않은 상황. 컴파일, 런타임에 일어날 수 있으며, 적절한 예외 처리를 통해 복구 가능하다. ex) NullPointException

💡 따라서 적절한 예외 처리를 통해 예외 상황에 대응하는 코드를 작성하는 것이 중요하다. 예외 처리 시에는 예외의 종류에 맞는 적절한 처리 방법을 선택하여 적용해야 한다.


예외의 종류

예외는 크게 Checked ExceptionUnchecked Exception로 나눌 수 있다. 종류에 따라 강제 예외 처리, 트랜잭션 롤백 여부, 예외 체크 시점 등이 나뉘므로 차이점을 파악할 필요가 있다.


Checked Exception

: Exception 을 직접 상속받는 모든 예외. 컴파일 단계에서 컴파일러가 예외처리 여부를 확인하며, 발생 가능성이 있다면 반드시 예외처리를 해야한다.

  • 예시) IOException



Unchecked Exception

: RuntimeException을 상속받는 모든 예외. 예외 처리를 컴파일 시점에 확인하지 않으며, 컴파일러가 강제하지 않으므로 프로그램 실행 중 예외가 발생할 수 있다.

  • 예시) NullPointerException



Runtime Exception

: 런타임 중에 발생할 수 있는 예외이며 Unchecked Exception을 대표하는 예외이다. 예외 처리를 컴파일 시점에 확인하지 않으며, 컴파일러가 강제하지 않으므로 프로그램 실행 중 예외가 발생할 수 있다.



Checked vs Unchecked

Checked ExceptionUnchecked Exception
확인 시점컴파일 단계런타임 단계
강제 예외처리 여부✖️
회복 가능성✖️
스프링 트랜잭션 롤백 여부✖️
  • 강제 예외처리 여부 : 강제적으로(명시적으로) 예외 처리를 해두어야 한다. 예외 처리를 하지 않으면 컴파일이 되지 않는다.

  • 회복 가능성 : 적절한 예외처리를 통해 프로그램을 계속 실행할 수 있는지에 대한 여부

  • 트랜잭션 롤백 여부 : 트랜잭션 상황에서 예외가 발생했을 때 롤백이 가능한지 여부

Unchecked Exception의 경우 컴파일 시점에서 예외 처리를 강제하지 않으므로, 적절한 예외 처리를 하지 않을 시 런타임 중에 예외가 발생하게 되면 프로그램이 강제적으로 종료될 수 있다. 스프링 프레임워크는 트랜잭션 상황에서 Unchecked Exception 발생 시 롤백을 하도록 처리한다.

반면에, Checked Exception는 예외 처리를 구현하여도 스프링 프레임워크의 트랜잭션 상황에서 발생 시 롤백이 되지 않고 Commit이 된다.

즉, 상품 결제와 같은 트랜잭션 상황에서 잔고 부족 등으로 Checked Exception이 발생 시 롤백이 되지 않고 Commit이 되어 DB에 반영될 수 있다.

  • 예시) 상품 결제에서 잔고 부족으로 Checked Exception 발생 시, 사용자의 잔고는 차감되지 않지만 결제 정보가 생성되는 등 일부 데이터가 DB에 반영(Commit)되는 경우

반대로 Unchecked Exception 상황에서도 롤백이 아닌 Commit을 통해 상태 일관성을 유지해야 하는 경우가 생긴다. 이 경우는 예외가 발생하더라도 트랜잭션을 롤백하지 않고, 상태 일관성을 유지하기 위해 특정 작업은 DB에 반영하고 예외를 처리해야 한다.

  • 예시) 상품 결제 후 결제 확인 알림 발송에서 Unchecked Exception가 발생하더라도 결제 정보는 DB에 반영이 되어야하는 경우


각각의 경우에서 어떻게 예외처리를 해야할까?


예외 처리 방법

방법1: @TransactionalrollbackFor 속성

@TransactionalrollbackFor 속성을 이용하여 롤백을 하도록 처리하는 방법이다.

@Transactional(rollbackFor = {Exception.class})

rollbackFor은 디폴트 값으로 RuntimeException.class, Error.class 를 가지므로 Unchecked Exception에 대해서만 롤백을 수행한다.

따라서 Checked Exception의 경우 따로 명시를 해주어야 한다.

@Transactional(rollbackFor = IOException.class)		// 특정 예외에 대하여 롤백 수행

@Transactional(rollbackFor = Exception.class)		// 모든 예외에 대하여 롤백 수행

방법2: Checked/Unchecked 예외를 상속하도록 바꾸기

Unchecked ExceptionChecked Exception으로 처리할 수 있다. Unchecked Exception (ex. RuntimeException)은 Checked ExceptionException을 상속하므로 Exception으로 예외를 발생시켜 처리하도록 할 수 있다.


그러나

트랜잭션에서 롤백이 되지 않고 Commit이 되는 것이 항상 안 좋은 것인가?

개발자는 코드 작성 시 어떤 예외를 발생시킬지, 예외 발생 시 어떻게 처리할지 예외처리를 선택할 수 있으므로, 의도에 따라 적절히 예외 종류를 고려하여 구현할 필요가 있다.

어떤 방법이 적절한지는 공부 후 보충하여 작성해보겠다.

참고

https://docs.oracle.com/javase/tutorial/essential/exceptions/index.html
https://inpa.tistory.com/entry/JAVA-%E2%98%95-UnChecked-Exception%EA%B3%BC-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EC%9D%98-%EC%98%A4%ED%95%B4%EC%99%80-%EC%A7%84%EC%8B%A4
https://inpa.tistory.com/entry/JAVA-%E2%98%95-%EC%97%90%EB%9F%ACError-%EC%99%80-%EC%98%88%EC%99%B8-%ED%81%B4%EB%9E%98%EC%8A%A4Exception-%F0%9F%92%AF-%EC%B4%9D%EC%A0%95%EB%A6%AC
https://velog.io/@jay_k56/Spring-Transactional%EC%9D%98-rollback%EA%B3%BC-%EC%A3%BC%EC%9D%98%EC%A0%90

profile
백엔드 개발도 락이다

1개의 댓글

comment-user-thumbnail
2025년 3월 24일

우레님 덕분에 스프링에 적절한 예외를 사용해야하는 법을 학습했습니다~
일목요연하게 정리해주셔서 감사합니다^^

답글 달기