본문 바로가기
JAVA BASE/Exception(예외)

04. [자바] 예외(만들기, 되던지기, 연결)

by staticClass 2020. 12. 22.

사용자지정의 예외 만들기

필요에 따라 새로운 예외 클래스를 정의하여 사용할 수 있고
보통 Exception클래스 또는 RuntimeException클래스로부터 상속받아 클래스를 만게 되고
필요에 따라서 알맞은 예외 클래스를 선택할 수 있다.

class customException extends Exception {
    customException(String msg) {  // 문자열을 매개변수로 받는 생성자
        super(msg);  // 조상인 Exception클래스의 생성자를 호출한다.
    }
}

기존에는 Exception을 상속받아서 'checked예외'로 작성하는 경우가 많았지만
요즘은 RuntimeException을 상속받아 예외처리를 선택적으로 할 수 있게 작성하는 쪽으로
변해가고 있다.

class customRuntimeException extends RuntimeException {
    customRuntimeException(String msg) {  // 문자열을 매개변수로 받는 생성자
        super(msg);  // 조상인 customRuntimeException클래스의 생성자를 호출한다.
    }
}

필요에 따라 예외처리의 여부를 선택할 수 있는 'unchecked예외'가 강제적인
'checked예외'보다 더 환영받고 있다.

예외 되던지기(exception re-throwing)

메서드에서 발생 하는 예외가 여러개 일 때, 몇 개는 try-catch문을 통해 메서드에서 자체적으로 처리하고
나머지는 선언부에 지장하여 호출한 메서드에서 처리하도록 할 수 있다.

public static void main(String[] args) {
    try {
        method1();
    } catch (Exception e) {
        System.out.println("main()에서 예외가 처리 되었습니다.");
    }
}

static void method1() throws Exception{
    try {
        throw new Exception();
    } catch (Exception e) {
        System.out.println("method1()에서 예외가 처리 되었습니다.");
        throw e;        // 다시 예외를 발생시킨다.
    }
}
결과 : 
method1()에서 예외가 처리 되었습니다.
main()에서 예외가 처리 되었습니다.

method1()과 main() 양쪽의 catch블럭이 모두 수행되었다.
method1()의 catch블럭에서 예외를 처리하고 throw를 통해 다시 예외를 발생시키고
이를 다시 main()에서 한 번 더 처리하였다.

만일 메서드가 void가 아닌 리턴값이 있는경우에 catch문에도 return이 있어야 하지만
return 대신 throw를 사용 할 수도 있다.

static int method1() throws Excpetion {
    try {
        System.out.println("method1()이 호출되었습니다.");
        return 0;
    } catch(Exception e) {
        e.printStackTrace();
//        return 1; // catch블럭 내에도 return문이 필요하지만
        throw new Exception(); // return문 대신 예외를 호출해도 된다.
    } finally {
        System.out.println("method1()의 finally 블럭이 실행되었습니다.");
        // finally블럭 내에도 return을 사용 할 수 있고 이곳에 return을 작성하면
        // 앞서 작성해둔 try블럭과 catch블럭의 return이 아닌
        // finally의 return이 반환된다.
    }
}

연결된 예외(chained exception)

예외가 다른 예외를 발생 시킬 수 있는데 예를 들어 예외 A가 예외 B를 발생시켰다면
A를 B의 '원인 예외(cause exception)'라고 한다.

static void method1() throws Excpetion {
    try {
        System.out.println("method1()이 호출되었습니다.");
    } catch(Exception e) {
        customException ce = new customException();    // 예외 생성
        ce.initCause(e); // customException의 원인 예외를 Exception으로 지정
        throw ce;         // customException을 발생시킨다.
    } 
}

먼저 customException를 생성한 후에, intiCause()로 Exception를 customException의
원인 예외로 등록한 뒤 'throw'로 이 예외를 던진다.

initCause()는 Exception클래스의 조상인 Throwable클래스에 정의되어 있기 때문에
모든 예외에서 사용이 가능하다.

Throwable initCause(Throwable cause) 지정한 예외를 원인 예외로 등록
Throwable getCause()                 원인 예외를 반환

발생한 예외를 원인 예외로 등록하여 다시 예외를 발생시키는 이유는
첫번째 : 여러가지 예외를 하나의 큰 분류의 예외로 묶어서 다루기 위해서이다.

두번째 : checked 예외를 unchecked 예외로 바꿀 수 있도록 하기 위해서이다.

static void method(){
    try {
        throw new Exception1();
    } catch (Exception1 e) {
        throw new RuntimeException(new Exception1());
    }
}

class Exception1 extends Exception {
    public Exception1() {
        super();
    }
}

Exception1은 Exception의 자손이므로 반드시 예외 처리를 해야하는데,
이 예외를 RuntimeException으로 감싸버렸기 때문에 unchecked가 되었다.

댓글