3) 예외 클래스와 예외처리 방법
자바의 예외 클래스에는 모든 클래스의 공통부모가 되는 클래스(조상 클래스)로 Exception 클래스가 있다. 모든 자바 클래스는 Object클래스를 공통부모로 가지기 때문에 Exception클래스 역시 Object의 자식 클래스이다. Exception클래스는 크게 두 가지로 분류한다. RuntimeException클래스와 그 외의 클래스이다.
이 두가지 클래스를 구분하는 기준은 컴파일 가능여부라 할 수 있다. RuntimeException클래스를 상속받는 자식 클래스들은 주로 치명적인 예외 상황을 발생시키지 않는 예외들로 구성된다. 즉, 컴파일 단계에서 예외를 검사하지 않는다. 이러한 점 때문에 Unchecked Exception이라고도 한다. 하지만 오해해선 안 될 것이, 예외처리를 하지 않아도 된다는 뜻은 아니다. 개발자의 경험에 의거해 예외가 발생 가능한 코드에 대해 예외처리를 알아서 해주어야 한다.
반면, 이외의 클래스들은 컴파일 과정에서 예외를 검사하기 때문에 예외처리를 하지 않으면 컴파일 에러가 발생한다. 컴파일 단계에서 발생 가능한 예외를 대부분 처리할 수 있기 때문에 Checked Exception이라고도 한다. 대표적인 런타임 예외 클래스들에 대해 알아보자.
① ArithmeticException
- 위 코드는 일반적인 상황에서는 제대로 동작하나, n2에 0이 입력되면 예외가 발생한다. 이처럼 수학적 연산에서 발생되는 예외가 ArithmeticException클래스에 해당한다. 당연히 컴파일은 가능하기 때문에 RuntimeException에 속한다.
② NullPonterException
- 위 코드 또한 예외를 발생시킨다. 그 이유는 null값을 갖는(참조할 수 없는) 객체에 접근하고 있기 때문이다. 이와 같이 객체를 생성하지 않고 멤버에 접근하는 경우에 발생되는 예외가 NullPointerException에 해당한다. 이 또한 컴파일에러는 아니기에 RuntimeException이다.
③ ArrayIndexOutOfBoundsException
- 위와 같이 배열의 인덱스 범위를 초과하여 사용하는 경우 발생되는 예외가 ArrayIndexOutOfBoundsException에 해당한다. C++에선 컴파일에러사항이나 Java에서는 런타임에러이다.
④ NumberFormatException
- 문자열을 int형으로 변환할 때 변환할 수 없는 값이 포함된 경우 발생되는 예외이다.
⑤ ClassCastException
- 레퍼런스 형변환이 잘못된 경우 발생하는 예외이다.
- 예외를 처리하는 방법에는 위에서 설명한 try-catch-finally이외에도 예외 떠넘기기, 사용자 정의 예외 클래스 등이 있다.
- 메서드를 호출한 곳으로 예외처리를 떠넘길 때에는 throws를 사용한다. 당연히 넘겨받은 예외를 처리하기 위해선 메서드를 호출하는 부분이 try-catch문으로 감싸져 있어야 한다.
- 위 예시에는 throwTest를 호출하고 있는 main메서드로 예외를 throw 한다. 이 때, throwTest함수는 try문에, 예외 발생 시 실행문은 catch안에 적혀있어야 한다.
- 참고로, throw와 throws는 형태는 비슷해 보이지만 사용법이 완전 다르다. throw는 예외를 고의적으로 발생시키기 위해 사용한다.
⑥ 사용자 정의로 예외 클래스
- 사용자 정의로 예외 클래스를 만들고 싶을 때에는 일반 예외의 경우 Exception을 상속받고, 실행 예외의 경우 RuntimeException을 상속받는다.
- 보통 클래스 안에는 두 개의 생성자 선언부만 포함하는게 일반적이다. 메서드나 변수를 선언하는 것이 가능은 하지만, 잘 쓰이지 않는다.
- 아래의 예시를 보자. 출금금액은 예금금액보다 많을 수 없기 때문에 예외처리를 해주어야 한다.
- 이 때, 생성자는 디폴트 생성자와 message 출력을 위해 String을 입력 받는 생성자를 선언한다.
- 참고로 super()는 부모클래스의 생성자를 자식에서 호출할 때, 사용하는 키워드로 입력받은 message를 Exception클래스에 전달하므로 getMessage()명령을 사용할 수 있게 된다.
[이미지 출처]