[Java] 예외 처리

21. 예외처리

자바 예외 처리

  • 자바는 프로그램 실행 중에 발생할 수 있는 예상치 못한 상황 즉, 예외(Exception)을 처리하기 위한 메커니즘을 제공한다.
  • try, catch, finally, throw, throws
  • 예외 처리가 필요한 이유
    • 외부 서버와 통신 할 때 다양한 문제들이 발생한다.
      • 외부 서버와의 연결 실패, 데이터 전송 문제
    • 예외 처리를 사용하면 정상 흐름과 예외 흐름을 명확하게 분리할 수 있다.

예외 계층

image
  • Object : 예외도 객체이므로, 예외의 최상위 부모도 Object이다.
  • Throwable : 최상위 예외로 하위에 ExceptionError가 있다.
  • Error : 메모리 부족, 심각한 시스템 오류와 같은 애플리케이션에서 복구 불가능한 시스템 예외이다.
    • 개발자는 이 예외를 잡으려고 하면 안됨
  • Exception : 체크 예외
    • 애플리케이션 로직에서 사용할 수 있는 실질적인 최상위 예외
    • RuntimeException을 제외한 하위 예외는 컴파일러가 체크하는 체크 예외이다.
    • 발생한 예외를 개발자가 명시적으로 처리해야한다.
      • 처리하지 않으면 컴파일 오류가 발생한다.
  • RuntimeError : 언체크 예외, 런타임 에러
    • 컴파일러가 체크하지 않는 언체크 예외
    • 하위 예외는 모두 언체크 예외
    • 발생한 예외를 명시적으로 처리하지 않아도 된다.

예외 기본 규칙

  1. 예외는 잡아서 처리하거나, 밖으로 던져야 한다.
    • 자바 main() 밖으로 예외를 던지면 예외 로그를 출력하면서 시스템이 종료된다.
  2. 예외를 잡거나 던질 때 지정한 예외뿐만 아니라 그 예외의 자식들도 함께 처리할 수 있다.

체크 예외

  • Exception과 하위 예외 (RuntimeException 제외)
  • 체크 예외는 잡아서 처리하거나, 밖으로 던지도록 선언해야 한다.
    public class Client {
      public void call() throws MyCheckedException {
          throw new MyCheckedException("ex");
      }
    }
    
    public class MyCheckedException extends Exception {
      public MyCheckedException(String message) {
          super(message);
      }
    }
    
    • throw 예외 : 새로운 예외 발생
      • 예외는 객체이므로 객체를 new로 먼저 생성하고 예외를 발생시킨다.
    • throws 예외 : 발생시킨 예외를 메서드 밖으로 던질 때 사용한다.
    • MyCheckedException : Exception 예외를 상속받은 체크 예외
      • super(message)로 전달한 오류 메시지는 Throwable에 있는 detailMessage에 보관된다.
      • getMessage()를 통해 오류메세지를 조회 가능하다.
  • 예외를 잡아서 처리하는 코드
    public class Service {
      public void callCatch() {
          try {
              client.call();
          } catch (MyCheckedException e) {
              //예외 처리 로직
              System.out.println("예외 처리, message= " + e.getMessage());
          }
          System.out.println("정상 흐름");
      }
    }
    
    public class CheckedCatchMain {
      public static void main(String[] args) {
          Service service = new Service();
          service.callCatch();
          System.out.println("정상 종료");
      }
    }
    
    • client.call()에서 MyCheckedException 예외가 발생하고, 그 예외를 Service.callCatch()에서 잡는다.
    • 예외 처리 시 try ~ catch(...)를 사용해서 예외를 잡는다.
      • try 코드 블럭에서 발생하는 예외를 잡아서 catch로 넘긴다.
      • 만약 catch의 대상에 예외가 없으면 밖으로 던져야 한다.
      • catch에 예외 지정 시 하위 타입예외까지 모두 잡아준다.

  • 예외를 밖으로 던지는 코드
    public class Service {
      public void callThrow() throws MyCheckedException {
          client.call();
      }
    }
      
    public class CheckedThrowMain {
      public static void main(String[] args) throws MyCheckedException {
          Service service = new Service();
          service.callThrow();
          System.out.println("정상 종료");
      }
    }
    
    • throws를 사용해서, 밖으로 던질 예외를 지정한다.
    • Service.callThrow()에서 예외를 처리하지 않고 밖으로 던졌기 때문에 예외가 main()까지 올라온다.
      • main()에서는 예외가 밖으로 던져져서 예외 정보와 스택 트레이스를 출력하고 프로그램이 종료된다.
  • 체크 예외의 장단점
    • 장점 : 개발자가 실수로 예외를 누락하지 않도록 컴파일러를 통해 문제를 잡아준다.
    • 단점 : 모든 예외를 반드시 잡거나 던져야 해서 번거롭다.

언체크 예외

  • RuntimeException과 하위 예외
  • 컴파일러가 예외를 체크하지 않는다.
  • 예외를 던지는 throws를 선언하지 않고 생략 가능하다. 생략한 경우 자동으로 예외를 던진다.
    public class Service {
      Client client = new Client();
    
      public void callCatch() {
          try {
              client.call();
          } catch (MyUncheckedException e) {
              //예외 처리 로직
              System.out.println("예외 처리, message= " + e.getMessage());
          }
          System.out.println("정상 로직");
      }
    
      public void callThrow() {
          client.call();
      }
    }
    
    public class UncheckedCatchMain {
      public static void main(String[] args) {
          Service service = new Service();
          service.callCatch();
          System.out.println("정상 종료");
      }
    }
    
    public class UncheckedThrowMain {
      public static void main(String[] args) {
          Service service = new Service();
          service.callThrow();
          System.out.println("정상 종료");
      }
    }
    
    • 언체크 예외도 필요한 경우 예외를 잡아서 처리할 수 있다.
    • 예외를 밖으로 던질 때는 체크 예외와 다르게 throws 예외를 선언하지 않아도 된다.

    • 언체크 예외의 장단점
      • 장점 : 신경쓰고 싶지 않은 언체크 예외를 무시할 수 있다. throws 생략
      • 단점 : 체크예외는 컴파일러가 예외 누락을 잡아주지만 언체크 예외는 개발자가 실수로 예외를 누락할 수 있다.




김영한의 실전 자바 중급 1편을 참고하였습니다

© 2021. All rights reserved.

yaejinkong의 블로그