예외 블랙홀

예외가 발생했을때 그것을 catch 블록을 써서 잡아내고 아무것도 하지 않고 넘어가 버리는 건 매우 위험함

→ 원치 않는 예외가 발생하는 것보다도 훨씬 더 나쁜 일

→ 발생한 예외로 인해 예상치 못한 다른 문제를 일으킬 것

→ 더 큰 문제는 그 시스템 오류나 이상한 결과의 원인이 무엇인지 찾아내기가 매우 힘들다는 점

무의미하고 무책임한 throws

throws Exception이라는, 모든 예외를 무조건 던져버리는 선언을 모든 메소드에 기계적으로 넣는 것 결과적으로 적절한 처리를 통해 복구될 수 있는 예외상황도 제대로 다룰 수 있는 기회를 박탈당한다.

예외의 종류와 특징

Error

java.lang.Error 클래스의 서브 클래스들

시스템에 뭔가 비정상적인 상황이 발생했을 경우 사용(주로 자바 VM에서 발생)

애플리케이션 코드에서 못 잡음

시스템 레벨에서 특별한 작업을 하는 게 아니라면 애플리케이션에서는 이런 에어에 대한 처리는 신경 쓰지 않아도 된다.

Exception과 체크 예외

java.lang.Exception 클래스와 그 서브크래스로 정의되는 예외

에러와 달리 개발자들이 만든 애플리케이션 코드의 작업 중에 예외상황이 발생했을 경우에 사용

Exception 클래스는 다시 체크 예외와 언체크 예외로 구분

  • 체크 예외
    • Exception 클래스의 서브클래스이면서 RuntimeException 클래스를 상속하지 않은 것들
    • 일반 적으로 예외라고 하는 경우 체크 예외라고 생각해도 될것
    • 체크 예외가 발생할 수 있는 메소드를 사용할 경우 반드시 예외를 처리하는 코드를 함께 작성해야 함
  • 언체크 예외
    • RuntimeException을 상속한 클래스들

RuntimeException은 Exception의 서브클래스이므로 Exception의 일종이긴 하지만 자바는 이 RuntimeException과 그 서브클래스는 특별하게 다룬다.

RuntimeException과 언체크/런타임 예외

java.lang.RuntimeException 클래스를 상속한 예외들

명시적인 예외처리를 강제하지 않기 때문에 언체크 예외라고 불림 또는 런타임 예외라고도 함

에러와 마찬가지로 catch 문으로 잡거나 throws로 선언하지 않아도 됨(명시적으로 잡거나 throws로 선언해줘도 상관 없음)

주로 프로그램의 오류가 있을 때 발생하도록 의도된 것들 ex) NullPointerException, IllegalArgumentException

개발자가 잘 만들면 됨

예외 처리 방법

예외 복구

예외상황을 파악하고 문제를 해결해서 정상 상태로 돌려놓는 것

예외처리 회피

예외처리를 자신이 담당하지 않고 자신을 호출한 쪽으로 던져버리는 것

자신이 처리하지 않고 회피하는 방법

throws 문으로 선언해서 예외가 발생하면 알아서 던져지게 하거나 catch 문으로 일단 예외를 잡은 후에 로그를 남기고 다시 예외를 던지는 것

반드시 다른 오브젝트나 메소드가 예외를 대신 처리할 수 있도록 던져줘야 함

단, 콜백과 템플릿처럼 긴밀하게 역할을 분담하고 있는 관계가 아니라면 자신의 코드에서 발생하는 예외를 그냥 던져버리는 건 무책임한 책임회피일 수 있다.

예외 전환

예외 회피와 비슷하게 예외를 복구해서 정상적인 상태로는 만들 수 없기 때문에 예외를 메소드 밖으로 던지는 것

발생한 예외를 그대로 넘기는 게 아니라 적절한 예외로 전환해서 던진다는 특징이 있다.

보통 두 가지 목적으로 사용됨

  • 내부에서 발생한 예외를 그대로 던지는 것이 그 예외상황에 대한 적절한 의미를 부여해주지 못하는 경우에, 의미를 분명하게 해줄 수 있는 예외로 바꿔주기 위해서
    • 보통 전환하는 예외에 원래 발생한 예외를 담아서 중첨 예외로 만드는 것이 좋다.
  • 예외를 처리하기 쉽고 단순하게 만들기 위해 포장
    • 중첩 예외를 이용해 새로운 예외를 만들고 원인이 되는 예외를 내부에 담아서 던지는 방식은 같음
    • 주로 예외처리를 강제하는 체크 예외를 언체크 예외인 런타임 예외로 바꾸는 경우에 사용함

예외처리 전략

런타임 예외의 보편화

최근 등장하는 표준 스펙 또는 오픈소스 프레임워크에서는 API가 발생시키는 예외를 체크 예외 대신 언체크 예외로 정의하는 것이 일반화 되고 있다.

항상 복구할 수 있는 예외가 아니라면 일단 언체크 예외로 만드는 경향이 있다.

대게는 복구 불가능한 상황이고 보나마나 RuntimeException등으로 포장해서 던져야 할 테니 아예 API 차원에서 런타임 예외를 던지도록 만드는 것

애플리케이션 예외

애플리케이션 자체의 로직에 의해 의도적으로 발생시키고, 반드시 catch 해서 무언인가 조치를 취하도록 요구하는 예외를 일반적으로 애플리케이션 예외라고 한다.

정상적인 흐름을 따르는 코드는 그대로 두고, 예외 상황에서는 비즈니스적인 의미를 띤 예외를 던지도록 만드는 것 이때 사용하는 예외는 의도적으로 체크 예외로 만든다.

Ref.

이일민, “토비의 스프링 3.1”, 에이콘 출판사(2012)