Java - throw와 throws의 차이점

JS · 20 Sep 2020

throw와 throws 키워드는 비슷하지만 다른 용도로 사용됩니다.

throw는 Exception을 발생시킬 때 사용하는 키워드입니다. 만약 어떤 연산을 하다가 예상치 못한 일이 발생했을 때 Exception을 발생시켜 예외가 처리될 수 있도록 합니다. Application이 예외를 적절히 처리하지 못하면 프로그램이 죽거나 오동작하게 됩니다.

반면에 throws는 메소드를 정의할 때 사용하며, 이 메소드에서 발생할 수 있는 Exception을 명시적으로 정의할 때 사용합니다. 따라서 throws를 보면 잠재적으로 어떤 Exception을 발생될 수 있는지 쉽게 알 수 있습니다.

Throw

Integer.parseInt()는 인자로 전달된 문자를 Integer로 변환합니다. 만약 아래와 같이 숫자가 아닌 문자열을 인자로 전달하면 Exception이 발생하면서 프로그램이 죽게 됩니다.

String numStr = "11a";
int num = Integer.parseInt(numStr);

Output:

Exception in thread "main" java.lang.NumberFormatException: For input string: "11a"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:580)

Integer.parseInt()의 코드를 보면, 예상 밖의 인자가 전달되었을 때 Exception을 throw하도록 구현되어있습니다.

public static int parseInt(String s, int radix) throws NumberFormatException
{
    if (s == null) {
        throw new NumberFormatException("null");
    }
    if (radix < Character.MIN_RADIX) {
        throw new NumberFormatException("radix " + radix +
                " less than Character.MIN_RADIX");
    }
    ....
}

catch

만약 Exception이 발생했을 때 프로그램이 죽지 않게 하려면 다음과 같이 catch 키워드로 예외를 처리해야 합니다.

Integer.parseInt()에서 NumberFormatException이 발생하면 그 아래에 있는 코드들이 수행되지 않고 catch에 있는 코드가 실행됩니다.

String numStr = "11a";
int sum = 0;
int num = 0;
try {
    int num = Integer.parseInt(numStr);
    sum = sum + num;
} catch (NumberFormatException e) {
    // catch exception
    num = 0;
    sum = 0;
}

위의 예제는 NumberFormatException가 발생했을 때만 catch 코드가 수행되며 예외를 처리합니다. 만약 RuntimeException이 발생하면 예외를 처리하지 못하여 프로그램이 죽습니다. 만약 다음과 같이 catch (Exception e)으로 Exception에 대해서 예외를 처리하면 거의 모든 예외가 처리될 수 있습니다.

try {
    int num = Integer.parseInt(numStr);
} catch (Exception e) {
    // catch exception
}

다음은 NumberFormatException이 발생했을 때, 이 예외를 처리하고 IllegalArgumentException라는 다른 예외를 발생시키는 예제입니다.

String numStr = "11a";
try {
    int num = Integer.parseInt(numStr);
} catch (NumberFormatException e) {
    // catch exception
    throw new IllegalArgumentException("This string is not a number format");
}

예외의 종류를 변경하거나 메시지를 변경할 때 이렇게 구현할 수 있습니다.

위 코드를 실행하면 다음과 같이 재정의한 Exception과 메시지가 출력됩니다.

Exception in thread "main" java.lang.IllegalArgumentException: This string is not a number format
	at example.throwandthrows.Example.main(Example.java:36)

Multi catch

여러 Exception이 발생할 수 있는 경우, 다음과 같이 catch를 사용하여 여러개의 Exception을 잡을 수 있습니다.

try {
    int num = Integer.parseInt(numStr);
} catch (NumberFormatException e) {
    // catch exception
} catch (IllegalArgumentException e) {
    // catch exception
}

catch (Exception e)으로 거의 모든 예외를 잡을 수 있지만, 각각의 예외마다 다르게 처리해야하는 경우 위처럼 구현할 수 있습니다.

Exception, Throwable

Exception의 상속구조를 알아보려고 합니다.

다음 코드는 Exception 클래스입니다. Exception은 Throwable을 상속합니다.

public class Exception extends Throwable {
	...
}

그 외의 다른 많은 Exception들은 다음과 같이 Exception 클래스를 상속합니다.

public class RuntimeException extends Exception {
	...
}

대부분 Exception 클래스를 상속하기 때문에 catch (Exception e)와 같은 코드는 대부분의 예외를 잡아낼 수 있게 됩니다.

Custom Exception

Java는 IllegalArgumentException, NumberFormatException 등의 Exception을 기본적으로 제공하지만 다음과 같이 직접 Exception을 정의할 수도 있습니다.

public class InvalidNumberException extends Exception {
    public InvalidNumberException(String message) {
        super(message);
    }
}

위에서 정의한 Exception은 다음과 같이 사용될 수 있습니다.

if (desX < 0 || desY < 0) {
    throw new InvalidNumberException("It's not allowed a number under 0 : (x: "
            + desX + ", y: " + desY);
}

Throws

Throws는 메소드에서 잠재적으로 어떤 Exception이 발생할 수 있는지 명시하는 키워드입니다.

다음은 예제로 만든 InputEvent 클래스입니다. moveTo() 메소드의 정의에 throws NumberFormatException라고 정의함으로써, 이 메소드를 사용할 때 NumberFormatException가 발생할 수 있음을 알려줍니다.

public class InputEvent {
    private int x;
    private int y;

    public InputEvent(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void moveTo(int desX, int desY) throws NumberFormatException {
        if (desX < 0 || desY < 0) {
            throw new NumberFormatException("It's not allowed a number under 0 : (x: "
                    + desX + ", y: " + desY + ")");
        }
        this.x = desX;
        this.y = desY;
    }
}

그래서 사용할 때 다음과 같이 catch를 써주면 좋습니다.

InputEvent event = new InputEvent(10, 20);
try {
    event.moveTo(-1, -2);
} catch (NumberFormatException e) {
    // ignore
}

아래 코드는 Object 클래스의 wait()메소드입니다. 이런식으로 JavaDoc에 어떤 상황에서 Exception이 발생하는지 @throws으로 자세히 명시할 수 있습니다.

/**
 * Causes the current thread to wait until another thread invokes the
 .....
 * @throws  IllegalMonitorStateException  if the current thread is not
 *               the owner of the object's monitor.
 * @throws  InterruptedException if any thread interrupted the
 *             current thread before or while the current thread
 *             was waiting for a notification.  The <i>interrupted
 *             status</i> of the current thread is cleared when
 *             this exception is thrown.
 */
public final void wait() throws InterruptedException {
    wait(0);
}
댓글을 보거나 쓰려면 이 버튼을 눌러주세요.
codechachaCopyright ©2019 codechacha