throws
메서드 설계 시 예외 처리를 직접 하지 않는 경우에 사용한다.
메서드 이름 뒤에 throws Exception을 추가하면, 메서드에서 예외가 발생했을 때 메서드를 호출한 곳으로 exception이 던져진다.
Exception 및 이를 직접 상속받은 Exception을 throws 하는 메서드의 경우 이 메서드를 호출하는 쪽에서 반드시 예외 처리(handling)를 해야 한다. 하지 않는 경우 에러가 발생한다.
이와 달리 RuntimeException 및 이를 상속받은 예외를 throws 하는 메서드는 호출하는 쪽에서 매번 예외 처리를 하지 않아도 된다.
Exception 또는 RuntimeException 클래스를 상속 받아서 직접 Exception 클래스를 만들어 사용할 수 있다.
💻 예제 1
📝 소스 코드
public class Main {
public static void main(String[] args) {
TestClass test = new TestClass();
int result = test.divide(100, 0);
System.out.println("result = " + result);
System.out.println();
try {
test.divide2(100, 0);
} catch (Exception e) {
e.printStackTrace();
}
// test.divide3(200, 0);
for (int i = 0; i < 5; i++) {
System.out.println("i = " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("프로그램 종료 ...");
}
}
public class TestClass {
// try ~ catch
public int divide(int x, int y) {
int result = 0;
try {
result = x / y;
} catch (ArithmeticException ex) {
System.out.println(ex.getMessage());
}
return result;
}
// throws
public int divide2(int x, int y) throws Exception {
return x / y;
}
// throws RuntimeException
public int divide3(int x, int y) throws RuntimeException {
return x / y;
}
}
divide 메서드는 메서드 내부에서 try~catch문으로 예외 처리를 하였다.
divide2 메서드에서는 throws Exception을 사용하였다.
따라서 divide2 메서드를 호출한 Main 메서드에서, divide2 메서드 내에서 발생한 예외를 처리해야 한다. 하지 않는 경우 컴파일 에러가 발생한다.
main 메서드 내에 divide2 메서드 호출 부분을 try~catch문 내에 넣어 예외 처리를 해주었다.
만약 main 메서드에서 try~catch문을 사용하고 싶지 않다면 main 메서드 이름 뒤에 throws Exception을 해줘야 한다.
main() 메서드는 가상머신이 호출하는 메서드로, throws Exception을 사용하면 예외 상황 처리가 가상 머신으로 넘어간다.
가상 머신의 예외 처리는 처음으로 getMessage를 호출하고, 예외 상황이 발생해서 전달되는 과정을 출력한 뒤 프로그램을 종료한다.
divide3 에서는 throws RuntimeException을 사용하였다.
RuntiemException 및 그 자식 객체들을 throws 하는 경우는 catch를 해주지 않아도 컴파일 에러는 발생하지 않는다.
따라서 굳이 호출하는 쪽에서 매번 예외 처리를 할 필요가 없다.
📄 실행 결과
💻 예제 2
Exception 클래스를 직접 만들어 사용할 수 있다.
Exception 또는 RuntimeExeption 클래스를 상속받아서 만든다.
📝 소스 코드
import java.util.Scanner;
public class Main {
static Scanner sc = new Scanner(System.in);
// ScoreException 을 throws 하는 메서드
public static int inputScore() throws ScoreException {
int score = sc.nextInt();
if (score < 0 || score > 100) {
ScoreException ex = new ScoreException();
throw ex; // 예외 객체를 throw
}
return score;
}
public static void main(String[] args) {
// ScoreException을 catch
try {
System.out.println("국어 점수 입력 ");
int kor = inputScore();
System.out.println("kor = " + kor);
System.out.println("영어 점수 입력 ");
int eng = inputScore();
System.out.println("eng = " + eng);
} catch (ScoreException ex) {
System.out.println(ex.getMessage());
} finally {
sc.close();
}
}
}
public class ScoreException extends Exception {
public ScoreException() { // 기본 생성자
super("점수 입력 오류"); // Exception(String message) 생성자 호출
}
public ScoreException(String msg) {
super(msg);
}
}
Exception을 상속 받는 예외 클래스 ScoreException을 정의하였다.
ScoreException이 예외 클래스이므로 inputScore() 메서드에서 throws를 할 수 있다.
만약 입력받는 score가 0 미만이거나 100 초과인 경우 ScoreException 객체를 생성한 뒤 해당 예외 객체를 throw 한다.
ScoreException 클래스의 기본 생성자에서 super("점수 입력 오류");로 Exception(String message) 생성자를 호출한다.
따라서 예외가 발생하여 catch문이 실행되면 ex에 담긴 메시지를 출력하여 점수 입력 오류라는 문구가 출력된다.
📄 실행 결과
💻 예제 3
📝 소스 코드
import java.util.Scanner;
public class Main {
static Scanner sc = new Scanner(System.in);
// AgeInputException을 throws 하는 메서드
public static int inputAge() throws AgeInputException {
System.out.println("나이 :");
int age = sc.nextInt();
// 입력된 나이가 음수이면
// AgeInputException throw
if (age < 0) {
AgeInputException ex = new AgeInputException(age + " 은(는) 올바른 나이가 아닙니다.");
throw ex;
}
return age;
}
public static void main(String[] args) {
try {
int age = inputAge();
System.out.println("나이 : " + age);
} catch (AgeInputException ex) {
System.out.println(ex.getMessage());
} finally {
sc.close();
}
}
}
예제 2와 비슷한 예제이다.
AgeInputException 객체를 생성할 때 기본 생성자가 아닌 매개변수가 한 개 있는 생성자로 생성을 하였다.
따라서 예외가 발생하면 입력한 값이 올바른 나이가 아니라는 문구가 출력된다.
📄 실행 결과