만족은 하되 안주하지는 말자

기록해야 기억한다

프로그래밍/JAVA

[JAVA] 예외 (Exception)

D36choi 2020. 9. 29. 21:11
728x90

예외 Exception


에러란?

JVM 실행에 문제가 발생함을 의미. 자바에서는 에러 이외에 예외(Exception)라고 부르는 오류가 존재한다.

예외는 예외 처리 (Exception Handling) 을 통해 프로그램을 종료하지 않고 정상 실행 상태가 유지되도록 할 수 있다.

예외의 종류

예외에는 일반 예외와 실행 예외가 있는데 일반 예외는 컴파일 과정에서 검사한다. 만약 예외처리 코드가 없다면 컴파일과정에서 오류가 발생한다.
하지만 실행예외 (런타임예외)는 컴파일러가 검사하지 않는다
그렇기 때문에 개발자를 괴롭히는 에러는 대부분 실행 예외다. (=런타임예외)

예외 객체 트리

모든 예외 객체는 Exception 클래스를 상속받음

일반예외는 대신 RuntimeException을 상속받지 않는다. 그 외의 객체는 런타임예외 객체라 할 수 있다.

 

 

 

 

예외 처리 코드


런타임예외는 컴파일러의 체크가 없기 때문에 순전히 개발자의 지식과 경험에 의존해 해결해야 한다.
이런 예외 처리 코드는 try-catch 로 처리한다.

class Main {
  public static void main(String[] args) {
    String str1 = null;
    System.out.println(str1.toString());
  }
}

위의 코드는 NullPointerException 을 런타임 에러로 발생시킨다. String 객체에 null 처리가 되어있어 출력할 대상이 없기 때문이다.

try - catch 로 예외 처리를 해보자

class Main {
  public static void main(String[] args) {
    try {
      String str1 = null;
      System.out.println(str1.toString());
    } catch (NullPointerException e) {
      System.out.println("NullPointerException occurred");
    }

  }
}

try {..} 에는 실행 시킬 "예외가 발생할 가능성이 있는 코드" 를 위치하고, catch ( .. ) 의 매개변수로는 처리할 Exception 클래스 객체를
매개변수로 한다. 해당 매개변수가 해당 예외 객체가 리턴되면 catch { .. } 내의 코드를 실행한다.

널포인터 예외에 대해 print문이 동작함을 알 수 있다

catch (Exception e) 로 작성해도, Exception 은 모든 예외 객체의 부모 객체이므로 객체 캐스팅을 통해 정상 작동한다.

 

 

 

 

예외 떠넘기기 (Throw)


try-catch 로 예외 처리를 하는 방법 외에 Throws 를 이용한 방법도 있다.
try-catch 가 해당 메소드에서 발생한 예외를 스스로 해결하는 느낌이라면 Throws 는 메소드를 호출한 곳으로 예외처리를 떠넘긴다
라고 볼 수 있다.
리턴 타입 메소드명(매개변수) throws 예외클래스1, 2 { ... }
와 같은 형식으로 한다.

위에서도 언급했듯이 Exception 클래스를 활용하면 모든 예외를 던질 수 있다.

class Main {
  public static void main(String[] args) {
    try {
      action();
    } catch (ClassNotFoundException e)  {
      System.out.println("ClassNotFoundException occurred");
    }

  }

  public static void action() throws ClassNotFoundException{
    Class c = Class.forName("java.lang.String1");

  }
}

throws 키워드가 붙은 메소드는 반드시 try - catch 가 설정된 메소드 블록에서만 호출되어야 한다.
이러면 모든 하위 함수의 예시라 할 수 있는 action() 함수에서도 try-catch 를 일일이 할 필요없이 상위 메소드에서 처리를 한다면 반복적인 에러 처리가 필요없어진다.

만약 Main 에서도 throws 를 사용한다면?

그러면 예외를 떠넘겨 JVM 이 최종적으로 예외처리를 하게 되는데 이 것이 결국 Console 에 예외 내용이 출력되는 것을 의미한다.
별로 바람직하진 않다. 최종적으로 main 에서 모든 예외처리가 될 수 있게 하자.