반응형
예외 발생시키기
throw를 사용해서 프로그래머가 고의로 예외를 발생시킬 수 있다.
- 연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 만든 다음
- Exception e = new Exception(”고의로 발생시킴”);
- 키워드 throw를 이용해서 예외를 발생시킨다.
- throw e; → catch문에서
- throw new Exception(); 으로 한번에 던지기
try {
Exception e = new Exception("고의로 발생시킴");
throw e;
//throw new Exception();
} catch (Exception e) {
e.printStackTrace();
System.out.println("에러 메시지 : "+e.getMessage());
}
/*
java.lang.Exception: 고의로 발생시킴
at Anonymous.main(Anonymous.java:9)
에러 메시지 : 고의로 발생시킴
*/
💡 Exception인스턴스를 생성할 때, 생성자에 String을 넣어주면 String을 통해 Exception인스턴스에 메시지로 저장된다.
- 이 에러 메시지는 getMessage()를 통해서 얻을 수 있다.
checked예외, unchecked예외
throw를 사용해서 throw new Exception();을 try-catch문(예외처리)를 해주지 않으면 컴파일이 되지 않는다.
- Exception클래스와 그 자식들(checked예외) 발생한 경우 컴파일이 되지 않는다.
- throw new RuntimeException();은 컴파일이 된다?
- 실행하면, RuntimeException이 발생하여 비정상적으로 종료된다.
왜 RuntimeException은 컴파일이 될까?
public static void main(String[] args) {
throw new ArithmeticException(); //어라? 컴파일이 된다.
//throw new IOException(); 컴파일 에러 발생
}
// 에러 -> Unhandled exception: java.io.IOException
// throw new Exception(); -> Unhandled exception: java.lang.Exception
위에 설명한 것 처럼 예외 클래스들은 두 그룹으로 나눠질 수 있다.
- Exception: RuntimeException클래스와 그 자식들 제외한 나머지 클래스들
- Exception(자식들 checked예외): 사용자의 실수, 주로 외적인 요인에 의해 발생하는 예외
- RuntimceException과 자식들은 제외 (Exception이 예외 최상단 class라서 헷갈리는거 조심)
- Exception클래스에 checked예외가 포함되어 있어서 컴파일에러인거 같음 unchecked만 있음 상관 없을텐데..
- Exception(자식들 checked예외): 사용자의 실수, 주로 외적인 요인에 의해 발생하는 예외
- RuntimeException: RuntimeException클래스와 그 자식들 다포함해서 말한다.
- RuntimceException(자식들 unchecked예외): 프로그래머의 실수로 발생하는 예외(Java의 프로그래밍 요소들과 관계가 깊다.)
💡 RuntimeException클래스와 그 자식(unchecked예외)에 해당하는 예외는 프로그래머의 실수로 발생하는 것들이기 때문에 예외처리를 강제로 하지 않는다.
만약 RuntimeException클래스에 속하는 예외가 발생할 가능성이 있는 코드에도 예외처리를 해야한다면?
try {
int[] arr = new int[10];
System.out.println(arr[0]);
} catch (IndexOutOfBoundsException ie){
...
} catch (NullPointerException ne){
...
}
- 위 코드와 같이 참조 변수와 배열이 사용되는 모든 곳에 예외처리를 해주어야 할 것이다.
예외를 메서드에 선언하기
메서드의 선언부에 throws를 사용해서 메서드 내에서 발생할 수 있는 예외를 적어주면 된다.
void method() throws Exception1, Exception2, ... {
//메서드 내용
}
/*
throws Exception으로 메서드에 예외를 선언할 경우,
이 예외뿐만 아니라 그 자식타입의 예외까지 발생할 수 있다는 점 주의하자
*/
💡 예외를 발생시키는 throw와 예외를 메서드에 선언할 때 쓰이는 throws를 잘 구분하자!
- 메서드의 선언부에 예외를 선언함으로써 메서드를 사용하려는 사람이 메서드의 선언부를 보고, 메서드를 사용하기 위해서는 어떠한 예외들이 처리되어져야 하는지 쉽게 알 수 있다.
- 오버라이딩할 때는 단순히 선언된 예외의 개수가 아니라 상속관계 까지 고려해야 한다.
- 오바라이딩 할때 부모의 예외 개수보다 클 수 없기 때문이다.
어떤 종류의 예외가 발생할 가능성이 있는지 예측하기 힘든 프로그래머의 도움을 주고자 Java는 메서드를 작성할 때 메서드 내에서 발생할 가능성이 있는 예외를 메서드의 선언부에 명시하여 준다.
- 이 메서드를 사용하는 쪽에는 이에 대한 처리를 하도록 강요하기 때문에, 견고한 프로그램 코드 작성 가능
public class Test{
public static void main(String[] args) {
method2(); // 같은 클래스내의 static멤버이므로 객체 생성없이 직접 호출가능하다.
}
static void method2() throws ArithmeticException{
method1();
}
static void method1() throws ArithmeticException{
System.out.println(0/0);
}
}
/* 실행결과
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Anonymous.method1(Anonymous.java:14)
at Anonymous.method2(Anonymous.java:11)
at Anonymous.main(Anonymous.java:8)
*/
실행결과를 보면, 프로그램의 실행도중 java.lang.ArithmeticException이 발생하여 비정상적으로 종료했다는 것과 예외가 발생했을 때 호출스택(call stack)의 내용을 알 수 있다. (위 실행결과 읽는 법)
1. 예외가 발생했을 때, 모두 3개의 메서드(main, method1, method2)가 호출스택에 있었다.
2. 예외가 발생한 곳은 제일 윗줄에 있는 method1()이다.
3. main메서드가 method2()을 그리고 method2()은 method1()를 호출했다는 것을 알 수 있다.
위 예제를 보면 method1()에서 ‘System.out.println(0/0);’ 0으로 나누는 문장에 의해 예외가 발생했으나 try-catch문으로 예외처리를 해주지 않았다.
- method1()는 종료되면서 예외를 자신을 호출한 method2()한테 넘겨준다.
- method2()에서도 예외처리를 해주지 않아 종료되면서 예외를 자신을 호출한 main메서드한테 넘겨준다.
- main메서드에서 조차 예외처리를 해주지 않아 main메서드가 종료되어 프로그램이 예외로 인해 비정상적으로 종료된다.
- 예외가 발생한 메서드에서 예외처리를 하지 않고 자신을 호출한 메서드에게 예외를 넘겨줄 수 있다.
- 예외를 넘겨주는 것 일뿐 예외가 처리된 것은 아니기 때문에 한곳에는 try-catch문으로 예외처리 해야한다.
메서드 vs main (try-catch 어디에다가 둘까?)
- method2(), method1()에 try-catch를 넣으면 예외가 발생했을 때 메서드에서 예외를 처리
- main()은 예외가 발생한 사실을 모른다.
- 메서드 내에서 자체적으로 처리해도 되는 경우는 메서드 내에 try-catch문을 넣어서 처리하자
- 메서드 내에서 자체적으로 해결이 안되는 경우(사용자의 입력받았는데 예외가 발생해서 다시 사용자한테 입력을 받아와야 되는 경우)에는 예외를 선언해서, 호출한 메서드가 처리하도록 해야 한다.
static void test() {
throw new Exception("고의로 발생시킴");
// Unhandled exception: java.lang.Exception
}
static void test() throws Exception{ // 컴파일은 가능하다.
throw new Exception("고의로 발생시킴");
}
- 예외가 선언되어 있으면 Exception과 같은 checked 예외를 try-catch문으로 처리하지 않아도 컴파일 에러가 발생하지 않는다.
이전글
다음글
반응형
'책 > Java의 정석' 카테고리의 다른 글
[java] String 클래스와 StringBuffer (0) | 2023.02.09 |
---|---|
[java] 예외처리(3) (0) | 2023.02.07 |
[java] 예외처리(1) (0) | 2023.02.07 |
[java] instanceof 연산자 (0) | 2023.02.07 |
[java] 내부 클래스(inner class)와 익명 클래스(anonymous class) (0) | 2023.02.04 |