자바 예외 정리

NNIIE·2022년 9월 16일
0

java

목록 보기
3/7
post-thumbnail
post-custom-banner

예외 계층

  • Object : 예외도 객체이기 때문에 예외의 최상위 부모도 Object이다.

  • Throwable : 최상위 예외, 하위에 ExceptionError가 있다.

  • Error : 메모리 부족, 시스템 오류 같은 어플리케이션 레벨에서 복구가 불가능한 시스템 예외

    • 상위 예외를 잡으면 하위 예외까지 잡아버리기 때문에, 어플리케이션 로직에서는 Throwable 예외도 잡으면 안되고 Exception예외부터 필요한 예외로 잡아야 한다.
    • 언체크 예외에 속한다.
  • Exception : 체크 예외

    • 어플리케이션 로직에서 사용할 수 있는 실질적인 최상위 예외이다.
    • Exception과 그 하위예외는 컴파일러가 체크하는 예외이다. 단, RuntimeException은 아니다
  • RunTimeException : 언체크예외, 런타임예외

    • 컴파일러가 체크하지 않는다
    • RuntimeException과 자식예외는 모두 언체크 예외이다
    • 런타임 예외라고도 불린다.

예외 기본 규칙

예외는 폭탄 돌리기와 같다.
처리하거나 try catch 처리할수 없으면 throw 던져야 한다

예외를 처리하지 못하고 계속 던지게 되면?

  • 자바 main() 쓰레드의 경우 예외로그를 출력하며 시스템이종료된다
  • 웹어플리케이션의 경우 WAS가 해당 예외를 받아서 처리하는데, 주로 사용자에게 개발자가 지정한 오류페이지를 보여준다.

체크예외

Exception 과 그 하위 예외는 모두 컴파일러가 체크하는 체크 예외이다.
RuntimeException 은 예외로 한다.
체크 예외는 잡아서 처리하거나, 또는 밖으로 던지도록 선언해야한다.
그렇지 않으면 컴파일 오류가 발생한다.
Exception을 상속받은 예외는 체크 예외가 된다.

static class MyCheckedException extends Exception {
	public MyCheckedException(String message) {
 		super(message);
    }
}

MyCheckedExceptionException 을 상속받았다.
Exception 을 상속받으면 체크 예외가 된다.
참고로 RuntimeException 을 상속받으면 언체크 예외가 된다.


장단점

체크 예외는 예외를 잡아서 처리할 수 없을 때, 예외를 밖으로 던지는 throws 예외 를 필수로 선언해야한다. 그렇지 않으면 컴파일 오류가 발생한다. 이것 때문에 장점과 단점이 동시에 존재한다.

  • 장점

    • 개발자가 실수로 예외를 누락하지 않도록 컴파일러를 통해 문제를 잡아주는 훌륭한 안전 장치이다.
  • 단점

    • 개발자가 모든 체크 예외를 반드시 잡거나 던지도록 처리해야 한다
    • 의존관계 문제가 발생한다

활용

  • 기본적으로 언체크(런타임) 예외를 사용하자.

  • 체크 예외는 비즈니스 로직상 의도적으로 던지는 예외에만 사용하자 (반드시 처리해야 하는 문제일 경우)
    ex )

    • 계좌 이체 실패 예외

    • 결제시 포인트 부족 예외

    • 로그인 ID, PW 불일치 예외
      물론 이 경우에도 모두 체크 예외로 만들어야 하는 것은 아니다.
      다만 계좌 이체 실패처럼 매우 심각한 문제는 개발자가 실수로 예외를 놓치면 안된다고 판단할 수 있다.
      이 경우 체크 예외로 만들어 두면 컴파일러를 통해 놓친 예외를 인지할 수 있다.


문제점

  • 리포지토리는 DB에 접근해서 데이터를 저장하고 관리한다. 여기서는 SQLException 체크 예외를 던진다.
  • NetworkClient 는 외부 네트워크에 접속해서 어떤 기능을 처리하는 객체이다.
    여기서는 ConnectException 체크 예외를 던진다.
  • 서비스는 리포지토리와 NetworkClient 를 둘다 호출한다.
    • 따라서 두 곳에서 올라오는 체크 예외인 SQLExceptionConnectException 을 처리해야 한다.
    • 그런데 서비스는 이 둘을 처리할 방법을 모른다. ConnectException 처럼 연결이 실패하거나,
      SQLException 처럼 데이터베이스에서 발생하는 문제처럼 심각한 문제들은 대부분 애플리케이션
      로직에서 처리할 방법이 없다.
  • 서비스는 SQLExceptionConnectException 를 처리할 수 없으므로 둘다 밖으로 던진다.
    • method() throws SQLException, ConnectException
  • 컨트롤러도 두 예외를 처리할 방법이 없다.
    • method() throws SQLException, ConnectException
  • 웹 애플리케이션이라면 서블릿의 오류 페이지나, 또는 스프링 MVC가 제공하는 ControllerAdvice 에서 이런 예외를 공통으로 처리한다.
    • 이런 문제들은 보통 사용자에게 어떤 문제가 발생했는지 자세히 설명하기가 어렵다.
    • API라면 보통 HTTP 상태코드 500(내부 서버 오류)을 사용해서 응답을 내려준다.
    • 이렇게 해결이 불가능한 공통 예외는 별도의 오류 로그를 남기고, 개발자가 오류를 빨리 인지할 수
      있도록 메일, 알림(문자, 슬랙)등을 통해서 전달 받아야 한다. 예를 들어서 SQLException 이 잘못된
      SQL을 작성해서 발생했다면, 개발자가 해당 SQL을 수정해서 배포하기 전까지 사용자는 같은 문제를
      겪게 된다.

의존관계에 대한 문제

class Controller {
	public void request() throws SQLException, ConnectException {
 		service.logic();
	}
}

class Service {
	public void logic() throws SQLException, ConnectException {
 		repository.call();
 		networkClient.call();
 	}
}
  • Service, Controller 에서 java.sql.SQLException을 의존하게 된다.
  • 나중에 JDBC가 아닌 JPA같은 다른 기술로 변경하게 된다면 모든 코드를 고쳐야 하는 문제가 발생한다
  • 결국 OCP, DI 을 위반하게 된다

언체크예외

  • RuntimeException 과 그 하위 예외는 언체크 예외로 분류된다.
  • 컴파일러가 예외를 체크하지 않는다
  • 언체크 예외는 체크 예외와 기본적으로 동일하다. 차이가 있다면 예외를 던지는 throws 를 선언하지 않고,
    생략할 수 있다. 이 경우 자동으로 예외를 던진다.

체크 예외 VS 언체크 예외
체크 예외: 예외를 잡아서 처리하지 않으면 항상 throws 에 던지는 예외를 선언해야 한다.
언체크 예외: 예외를 잡아서 처리하지 않아도 throws 를 생략할 수 있다.


장단점

언체크 예외는 예외를 잡아서 처리할 수 없을 때, 예외를 밖으로 던지는 throws 예외 를 생략할 수 있다.
이것 때문에 장점과 단점이 동시에 존재한다.

  • 장점

    • 신경쓰고 싶지 않은 언체크 예외를 무시할 수 있다. 체크 예외의 경우 처리할 수 없는 예외를 밖으로 던지려면 항상 throws 예외 를 선언해야 하지만, 언체크 예외는 이 부분을 생략할 수 있다.
    • 신경쓰고 싶지 않은 예외의 의존관계를 참조하지 않아도 되는 장점이 있다.
  • 단점

    • 언체크 예외는 개발자가 실수로 예외를 누락할 수 있다.
      반면에 체크 예외는 컴파일러를 통해 예외 누락을 잡아준다.


활용

  • SQLException 을 런타임 예외인 RuntimeSQLException 으로 변환했다.
  • ConnectException 대신에 RuntimeConnectException 을 사용하도록 바꾸었다.
  • 런타임 예외이기 때문에 서비스, 컨트롤러는 해당 예외들을 처리할 수 없다면 별도의 선언 없이 그냥 두면 된다.
  • 런타임 예외 - 대부분 복구 불가능한 예외
    • 시스템에서 발생한 예외는 대부분 복구 불가능 예외이다. 런타임 예외를 사용하면 서비스나 컨트롤러가
      이런 복구 불가능한 예외를 신경쓰지 않아도 된다.
  • 런타임 예외 - 의존 관계에 대한 문제
    • 런타임 예외는 해당 객체가 처리할 수 없는 예외는 무시하면 된다. 따라서 체크 예외 처럼 예외를 강제로 의존하지 않아도 된다.
post-custom-banner

0개의 댓글