자바 예외 이해
예외 계층
- Object : 자바의 모든 객체는 Obejct를상속받는다. 예외도 마찬가지이다.
- Throwable : 최 상위 예외이다.
- Error : 메모리 부족이나 심각한 시스템 오류 등 복구불가능한 예외이다.
- Exception
- Checked : RuntimeException을 제외한 모든 예외를 체크예외라 한다.
- Unchekced : RuntimeException 하위의 모든 예외를 언체크예외라 한다.
예외 기본 규칙
예외는 폭탄돌리기와 같다. 예외를 처리하지 못하면 호출한 곳으로 예외를 던지고 예외를 처리할 수 있으면 처리하고 정상흐름으로 돌릴 수 있다.
예외를 처리하지 못하고 계속 던지면 어떻게 될까?
- 자바의 main() 쓰레드의 경우 에러 로그를 출력하면서 시스템이 종료된다.
- 웹 애플리케이션의 경우 예외가 발생한다고 시스템이 종료되면 안된다. WAS가 해당 예외를 받고 처리하는데, 주로 사용자에게 개발자가 지정한 오류 페이지를 보여준다.
체크 예외
- Exception을 상속받으면 체크예외가 된다. 체크예외는 컴파일 타임에 예외를 처리해야함을 강제한다.
- RuntimeException을 상속받으면 언체크 예외가 된다.
체크예외의 장단점
- 안전하게 코드를 작성할 수 있다. 예외를 놓치지 않고 처리하도록 강제한다.
- 하지만 모든 체크예외를 개발자가 다루는 것이 매우 번거롭다. 예외를 모두 챙겨야한다. 크게 신경쓰지 않아도 되는, 개발자가 잡아서 처리할 수 없는 예외들까지 다뤄야하는 문제가 발생한다.
언체크 예외
- RUnitmeException 과 그 하위 예외는 언체크 예외로 분류한다.
- 언체크 예외는 예외를 잡아서 처리하지 않아도 throws 를 해준다.
체크예외와 언체크예외의 차이
- 이 둘의 차이는 예외를 처리할 때에는 크게 차이가 없다.
- 그러나 예외를 처리하지 않고 던질 때 필수적으로 밖으로 던지는 코드를 선언하는가 선언하지 않는가의 차이가 있다.
- 이 둘의 차이가 별거 아닌거 같아보이지만 이를 활용할 때에는 많은 차이를 만든다.
체크 예외 활용
기본 원칙
- 기본적으로 언체크(런타임) 예외를 사용하자
- 체크 예외는 비즈니스 로직상 의도적으로 던지는 예외에만 사용하자
- 반드시 처리해야 하는 문제일 때만 체크 예외를 사용해야 한다.
- ex)
- 계좌 이체 실패 예외
- 결제시 포인트 부족 예외
- 로그인 ID, PW 불일치 예외
- 이 경우에도 100% 체크 예외로 만들어야 하는 것은 아니다. 다만 매우 심각한 문제는 개발자가 실수로 예외를 놓치면 안된다고 판단할 수 있다.
- 반드시 놓치면 안되는 예외는 체크예외로 만들 수 있다.
왜 위와같은 원칙을 적용해야할까? 체크예외로 개발자에게 안전한 코드를 강제할 수 있다면 좋은 게 아닐까?
두 가지 문제
- (복구 불가능한 예외) 물론 안전한 코드를 강제해줘서 좋다. 하지만 구체적인 예외를 전파하는 과정에서 해당 예외에 의존하는 코드가 여러 레이어로 전파가된다.
- (의존관계 문제) 우리가 처리할 수 없는 예외를 던지는 코드를 각 레이어에 전파함으로써 필요없는 의존성을 맺게되고 의존성이 변경되면 다같이 코드를 수정해야하는 문제를 야기한다.
- 네트워크 예외나 DB 예외와 같은 체크예외들은 서비스나 컨트롤러에서도 해결할 수가 없다.
- SQLExecption을 서비스, 컨트롤러에까지 throws 예외 처리를 해줘야한다.
- SQLException은 JDBC에 의존하는 예외인데 만약 SQLException이 JPAException으로 변경된다면 모든 레이어의 코드를 모두 변경해줘야한다.
- 주로 웹 애플리케이션에서는 이러한 Exception들을 ControllerAdvice에서 예외를 정해서 처리해준다.
- 네트워크 예외나 DB 예외와 같은 체크예외들은 서비스나 컨트롤러에서도 해결할 수가 없다.
해결방안
- 만약 최상위 타입인 Exception을 던지는 방법으로 해결하려면 어떻게 될까?
- 이 방법은 좋지 않다.
- 모든 CheckedException이 밖으로 던져지는 예외가 발생하므로 체크 예외가 무의미해진다.
언체크 예외 활용
- 기본적으로 체크예외는 체크 => 언체크로 변경하여 예외를 처리한다.
- 이렇게 처리하면 컨트롤러, 서비스 레이어 등 다른 레이어로 예외의 의존관계를 전파하지 않을 수 있다.
- 최근 라이브러리들은 대부분 런타임 예외를 기본으로 제공한다.
- 런타임 예외는 놓칠 수 있기 때문에 문서화가 중요하다.
예외 포함과 스택 트레이스
- 예외를 포함한 스택트레이스를 발생시키려면?
- 예외 생성자의 (Throwable cause) 로 생성자를 만들어주면 실제 기존 예외를 포함하여 확인할 수 있게된다.
- 예외를 전환할 때는 꼭! 기존 예외를 포함하여 만들어주자
Reference
- 스프링 DB 1편 - 데이터 접근 핵심 원리 by 김영한
'Java' 카테고리의 다른 글
Reflection, JDK 동적 프록시, CGLIB (0) | 2022.06.08 |
---|---|
Garbage Collector (정의와 종류) (0) | 2022.06.06 |
Java String이란? (StringBuilder, StringBuffer, String Iterning, String pool) (0) | 2022.06.04 |
JVM (Java Virtual Machine)과 메모리 영역 (0) | 2022.06.02 |
Effective Java - Item 42. 익명 클래스보다는 람다를 사용하라 (0) | 2021.06.19 |