억제된 예외

예외에서 사용할 수 있는 함수 중 addSuppressed()라는 함수가 있다.
이것을 어디서 어떻게 활용하는지 궁금했는데 다음과 같다.
간단한 예제로 이 코드를 실행해 보았을 때, 3개의 예외가 발생하지만 최종적으로 다음과 같이 ArithmeticException만 출력된다.

예외를 던질 때는 최종적으로 하나의 예외만 던질 수 밖에 없는데, addSuppressed()라는 최종적으로 던질 예외를 제외한 예외들을 억제된 예외로 추가할 수 있다.
- 억제된 예외 사용
실행 해보면 다음과 같이 NullPointerException이 억제된 예외로 등록되고 최종적으로 FileNotFountException이 throw된다.

그리고 이 억제된 예외는 try-with-resource에서도 사용되는데 다음과 같다.
- try-with-resource에서의 억제된 예외
DirtyResource는 AutoCloseable을 implements받아 try-with-resource구문에서 사용되면 자동으로 close함수가 실행된다. 이 때, NullPointerException이 발생한다고 가정을한다.그리고 accessResource() 함수를 실행하면 예외를 발생하도록 했을 때 다음과 같이 결과값이 나온다.

accessResource() 함수가 실행되며 RuntimeException이 발생되고 그 다음 close함수가 실행되는데, 이 때 close함수에서도 예외가 발생하면 accessResource에서 발생된 RuntimeException에 억제된 예외로 등록되는 것이다.
Cause
cause는 예외의 원인이 되는 상세 예외를 뜻한다.Enum의 valueOf() 함수를 사용했을 때 커스텀 예외를 던지고자 했을 때 이 커스텀 예외에 원인이 되는 예외를 등록해 상세한 예외를 명세할 수 있다.
- Caused by로 원인 예외가 등록된 것을 볼 수 있다.

예외 체이닝
상위 계층으로 예외가 전달될 때 예외를 새로운 예외에 포함시켜 전달하는 과정을 예외 체이닝, 래핑이라고 한다.
예외 체이닝이 필요한 이유?
예외 체이닝의 주요 목적은 본래의 예외를 여러 계층에 걸쳐 전달될 때 보존해주기 위해서다.예외를 보존함으로써 예외 스택을 추적하기 쉬워지면서 디버깅할 때 유용하다.다음은 예외 체이닝을 제대로 사용하지 않았을 경우다.
예외 체이닝이 부적절한 경우
아래와 같은 계층 구조를 가졌을때를 예로 들어본다.


예제와 같은 경우에는 3가지의 메소드 밖에 실행하지 않았기 때문에 계층 구조를 파악하는게 어렵지 않은데? 라고 생각할 수 있겠지만 많은 메소드를 거치는 경우 계층을 구별할 수 없어 디버깅할 때 어려움을 겪을 수도 있다.
이러한 방식보다 조금 더 개선된 방식을 제안한다.

이제 Custom Exception과 메시지로 예외를 확연하게 계층별로 구별할 수 있다.