안녕하세요, 여행벌입니다.

저번 포스팅에 이어서 예외 클래스에 대해서 포스팅해보겠습니다.


예외 클래스 ( Throwable 클래스 )

 저번 포스팅에서 예외가 발생하면 해당 예외 클래스의 인스턴스를 생성한다고 했습니다. 그럼 예외 클래스는 어떤 클래스들이 있고, 어떤 메소드가 있고, 어떤 구조로 이루어져 있는지 알아보겠습니다.

 

 자바의 최상위 클래스인 Object 클래스를 제외하고 예외 클래스의 최상위 클래스는 Throwable 클래스 입니다. Throwable 클래스에는 여러 가지 메소드가 정의되어 있는데, 자주 쓰이는 메소드 2가지만 알아보겠습니다.

// 예외의 원인을 담고 있는 문자열을 반환
public String getMessage()

// 예외가 발생한 위치와 호출된 메소드의 정보를 출력
public void printStackTrace()

 위의 2가지 메소드는 예외 상황을 파악할 때 자주 쓰이는 메소드이므로 알아두시면 좋습니다.

예외 클래스 구분

 예외 클래스의 최상위 클래스는 항상 Throwable 클래스 이지만, 세부적으로 들어가 보면 이를 상속하는 3가지 부류로 나뉩니다.

 예외 클래스의 상속 관계는 다음과 같습니다. 우리는 이를 기반으로 크게 3가지 부류로 예외 클래스를 나눌 수 있습니다.

 

1) Error 클래스를 상속하는 예외 클래스

2) RuntimeException 클래스를 상속하는 예외 클래스( 당연히 Excpetion 클래스도 상속 )

3) RuntimeException 클래스를 상속하지 않고 Excpetion 클래스만 상속하는 예외 클래스

1) Error 클래스를 상속하는 예외 클래스

 Error 클래스를 상속하는 예외 클래스는 'VirtualMachineError', 'IOError' 와 같이 우리가 처리할 수 없는 예외 상황을 의미하기 때문에 그냥 프로그램이 종료되도록 놔두고 이후에 원인을 파악해야 합니다.

 'VirtualMachineError' 는 자바 가상머신에 심각한 오류가 발생한 것이고, 'IOError' 는 입출력 관련해서 코드 수준 복구가 불가능한 오류가 발생한 상황입니다. 자바 프로그램이 임의의 파일에 데이터를 저장하는 중에 하드디스크에 물리적 오류가 생긴다는 등 우리가 해결할 수 없는 상황들을 뜻합니다.

2) RuntimeException 클래스를 상속하는 예외 클래스

 RuntimeException 클래스를 상속하는 예외 클래스 같은 경우는 우리가 자주 보게 되는 예외 상황들입니다. 대표적인 클래스는 다음과 같습니다.

 

1. java.lang.ArithmeticException // 0으로 나누기 등의 산술 오류

2. java.lang.InputMismatchException // 잘못된 입력을 한 경우

3. java.lang.ArrayIndexOufOfBoundsException // 배열의 인덱스를 잘못 참조한 경우

4. java.lang.NegativeArraySizeException // 배열 생성 시 길이를 음수로 지정하는 경우

5. java.lang.NullPointerException // null 객체를 잘못 참조한 경우

6. java.lang.ArrayStoreException // 배열에 적절치 않은 인스턴스를 저장하는 경우

 

 이 외에도 다양한 예외 클래스들이 있지만, 대체로 프로그래머가 예외 처리를 해야 하는 상황보다는 코드를 수정해야 하는 상황입니다.

3) Exception 클래스만 상속하는 예외 클래스

 3종류 중 Exception 클래스만 상속하는 예외 클래스가 가장 많습니다. 종류가 너무 많기 때문에 예외 상황을 마주칠 때마다 정리해두는 것을 추천합니다. 다른 예외 클래스와의 차이점은 Exception 클래스만을 상속하는 예외 클래스는 try ~ catch 문으로 처리하거나 다른 영역으로 처리를 넘긴다고 반드시 명시해야 한다는 점입니다. 그렇지 않으면 컴파일을 할 수 없습니다.

 

 정리하면, Error를 상속하거나 RuntimeException을 상속하는 예외의 발생은 코드 작성 과정에서 특별히 무언가를 하지 않아도 되지만, Exception 을 상속하는 예외의 발생에 대해서는 try ~ catch 문을 통해서 예외를 처리하거나 예외의 처리를 다른 영역으로 넘겨야 한다.

throws 키워드

 위에서 계속 예외의 처리를 다른 영역으로 넘긴다고 표현하고 있다. throws 키워드를 이용하면 현재 영역에서 발생한 예외를 다른 영역으로 처리해달라고 넘길 수 있다. 먼저, 간단한 코드를 통해서 예외가 발생할 때 호출 흐름이 어떻게 되는지 알아보자.

package Hello;

public class test{
	public static void method1() {
		method2();
	}
	public static void method2() {
		System.out.println(5 / 0); // 예외 발생
	}
	
	public static void main(String args[]) {
		try {
			method1();
		}
		catch(Throwable e) {
			e.printStackTrace();
		}
		System.out.println("프로그램이 정상적으로 종료");
	}
}

 메인 메소드에서 method1 메소드를 호출하고, method1 메소드에서는 method2 메소드를 호출하고, method2 에서는 0으로 나누는 ArithmeticException 이 발생합니다. printStackTrace 메소드를 이용해서 예외가 발생한 위치와 호출된 메소드의 정보를 출력해보았습니다.

[Output]
java.lang.ArithmeticException: / by zero
	at HelloWorld/Hello.test.method2(test.java:8)
	at HelloWorld/Hello.test.method1(test.java:5)
	at HelloWorld/Hello.test.main(test.java:13)
프로그램이 정상적으로 종료

  method2 에서 에러가 발생했지만, method1 을 호출하고, 다시 main을 호출한 것을 확인할 수 있습니다. 즉, 예외는 처리되지 않으면 그 책임이 넘어가고 그 끝은 main입니다. 위의 코드는 main 함수에서 try ~ catch 구문을 이용해 예외를 처리하였으므로, try~catch 문 뒤에 있는 출력이 정상적으로 돌아간 것을 확인할 수 있습니다.

 throws 키워드를 이용하면 특정 예외 상황에 대해서 처리를 넘길 수 있습니다.

	public static void method2() throws ArithmeticException {
		System.out.println(5 / 0); // 예외 발생
	}

 다음과 같이 throws 키워드를 이용하면 ArithmeticException이 발생했을 때, 예외 처리를 메소드를 호출한 영역으로 넘길 수 있습니다. 또, 다음과 같이 여러 가지 예외 상황은 넘긴다고 명시할 수도 있습니다.

	public static void method2() throws ArithmeticException, IOException{
		System.out.println(5 / 0); // 예외 발생
	}

직접 정의하는 예외 클래스

 프로그래머가 직접 예외 클래스를 정의하고 이를 기반으로 특정 상황에서 예외가 발생하도록 할 수도 있습니다. 핵심은 우리가 직접 정의하는 예외 클래스는 모두 Exception 클래스를 상속해야 합니다.

class MyError extends Exception{
	public MyError() {
		super("내가 정의한 에러발생!");
	}
}

 예외 클래스를 정의하는 방법은 간단합니다. 그럼 어떻게 사용하는지 알아보겠습니다.

package Hello;

import java.io.IOException;

class MyError extends Exception{
	public MyError() {
		super("내가 정의한 에러발생! 양수를 입력해주세요!");
	}
}
public class test{
	public static void method1(int n) throws MyError{
		if(n < 0)
			throw new MyError();
	}
	public static void main(String args[]) {
		try {
			method1(-5);
		}
		catch(Throwable e){
			e.printStackTrace();
		}
	}
}

 method1 에서 입력받은 수가 음수라면 throw new MyError() 를 통해 내가 정의한 예외 상황을 발생시킬 수 있습니다.

[Output]
Hello.MyError: 내가 정의한 에러발생! 양수를 입력해주세요!
	at HelloWorld/Hello.test.method1(test.java:13)
	at HelloWorld/Hello.test.main(test.java:17)

이상으로 예외 처리 및 예외 클래스 포스팅을 마무리해보겠습니다.

예외 처리는 항상 필요하지만, 너무 과한 예외 처리는 프로그램의 성능 저하를 초래하므로

조심하셔야 됩니다!

 

+ Recent posts