14장에서는 자바에서 제공하는 다양한 예외아 그 처리 방법을 알아본다. 이외에도 예외를 다른 곳에 전가하는 방법과 직접 예외 클래스를 생성해 사용하는 방법을 알아본다.
- 14.1 예외
- 14.2 예외 처리
- 14.3 예외 진가
- 14.4 사용자 정의 예외 클래스
14.1 예외
개발자가 프로그램을 작성하는 과정에서 실수를 하거나 사용자가 잘못된 값을 입력하면 오류가 발생할 수 있다. 다양하게 발생하는 오류 중 개발자가 해결할 수 있는 오류를 '예외(exception)' 이러한 예외가 발생했을 때 이를 적절히 처리하는 것을 '예외 처리'라고 한다.
14.1.1 예외와 에러의 차이점
자바에서 제공하는 예외 처리 메커니즘을 이해하기 전에 예외(exception)와 에러(eorror)의 의미를 정리할 필요가 있다. 먼저 예외는 '연산 오류, 숫자 포맷 오류 등과 같이 상황에 따라 개발자가 해결할 수 있는 오류'를 말한다. 여기서 '해결할 수 있는'의 의미는 오류 자체를 수정할 수 있다는 것이 아니라 오류가 발생했을 때 차선책을 선택하는 것을 말한다. 반면 에러는 자바 가상 머신 자체에서 발생하는 오류로, '개발자가 해결할 수 없는 오류'를 말한다. 오류가 발생했을 때 차선책을 제시함으로써 오류를 피하는 과정을 '예외 처리'라고 한다.
자바에서 예외의 최상위 클래스는 Exception 클래스, 에러의 최상위 클래스는 Error 클래스다. 이 2개의 클래스는 아래 그림에서 볼 수 있듯이 모두 Throwable 클래스를 상속하고 있다. 따라서 에러와 예외 모두 Throwable 클래스의 모든 기능을 포함한다. 어차피 에러가 발생하면 할 수 있는 것이 없으므로 예외에 대해 좀 더 자세하게 알아보자.
14.1.2 예외 클래스의 상속 구조
Throwable 클래스를 상속받은 Exception 클래스는 다시 일반 예외(checked exception) 클래스와 실행 예외(unchecked(runtime) exception) 클래스로 나뉜다. 다음 그림은 일반 예외와 실행 예외의 대표적인 클래스들이다.
Exception 클래스에게서 직접 상속받은 예외 클래스들이 처리하는 일반 예외는 컴파일 전에 예외 발생 문법을 검사하며, 예외 처리를 하지 않으면 문법 오류가 발생한다. 반면 RuntimeException 클래스를 상속받은 예외 클래스들이 처리하는 실행 예외는 컴파일 전이 아니라 실행할 때 발생하는 예외로, 예외 처리를 따로 하지 않더라도 문법 오류가 발생하지 않는다. 다만 프로그램 실행 시 프로그램이 강제 종료되는 이유는 대부분 실행 예외 때문이므로 이에 대한 세심한 주의가 필요하다.
여기서 '검사'는 예외의 실제 발생 여부를 검사하는 것이 아니라 예외가 발생할 수 있는 문법을 사용했는지를 검사하는 것을 의미한다.
14.1.3 일반 예외 클래스
앞에서 설명한 것처럼 일반 예외는 예외 처리를 하지 않으면 문법 오류를 발생시켜 컴파일 자체가 불가능하다.
이러한 일반 예외를 처리하는 일반 예외 클래스에 대해 알아보자.
- InterruptedException: Thread 예외 처리
- ClassNotFoundException: Class 메모리 로딩 유무 예외 처리
- IOException: 콘솔 혹은 파일에 데이터 쓰기(Wirte), 읽기(Read) 예외 처리
- FileNotFoundException: 해당 경로에 파일의 존재 유무 예외 처리
- CloneNotSupporedException: 클론 객체의 Cloneable 인터페이스 상속 유무
14.1.4 실행 예외
일반 예외는 예외 처리를 해 주지 않으면 문법 오류가 발생하기 때문에 실행 자체가 불가능한 반면, 실행 예외는 문법 오류가 발생하지 않는다. 그렇기 때문에 예외 처리 없이 컴파일과 실행이 가능하지만, 실행 중 실행 예외가 발생하면 프로그램은 강제 종료된다. 실행 예외를 처리하는 클래스는 Exception의 자식 클래스인 Runtime Exception 클래스의 자식 클래스들이다. 그럼 대표적인 실행 예외 클래스를 하나씩 알아보자.
- ArithmeticException: 산술 연산 예외 처리
- ClassCastException: 상속 관계에 있는 클래스 다운캐스팅 예외 처리
- ArrayIndexOutOfBoundsException: 배열의 인덱스 범위를 잘못 사용한 경우 예외 처리
- NumberFormatException: 문자열을 숫자로 변환 예외 처리
- NullPointerException: 참조 변수가 실제 객체를 가리키지 않은 상황의 예외 처리
14.2 예외 처리
앞에서 예외의 종류를 배웠으므로 이제 예외 처리 방법을 알아보자. 일단 예외 처리는 예외가 발생했을 때 처리하는 방법을 제공하는 문법 요소로, 예외 처리 구문이 포함되면 예외가 발생하더라도 프로그램이 계속 실행된다.
14.2.1 예외 처리 문법
예외 처리 문법은 다음과 같이 크게 3가지 요소(try, catch, finally)로 구성돼 있다.
// 예외 처리 문법 구조
try {
// 일반 예외,실행 예외 발생 가능 코드
} catch (예외클래스명 참조변수명) {
// 예외 발생했을 때 처리
} finally {
// 예외 발생 여부에 상관없이 무조건 실행. (finally{}는 생략 가능)
}
위의 try{} 블록과 catch(){} 블록 내의 공통된 코드는 예외 발생 여부와 상관없이 항상 실행되는 코드다. 따라서 다음과 같이 finally{} 블록을 사용해 작성하면 코드의 중복을 제거할 수 있다.
14.2.2 예외 처리 과정
그러면 실제 내부적으로 예외가 처리되는 메커니즘을 알아보자. 다음 예제는 분모가 0인 연산을 수행해 ArithmeticException 실행 예외가 발생하는 코드를 try{}
블록으로 감싸고, catch(){}
블록에서는 이 예외를 처리하는 구문을 작성했다. 마지막으로 finally{}
블록에서는 "프로그램 종료"라는 문자열을 출력하고 프로그램을 종료했다.
먼저 try{}
구문이 실행된다. 만일 예외가 발생하지 않는다면 catch(){}
블록은 실행되지 않을 것이고, finally{}
블록이 있다면 이 블록을 실행할 것이다. try{}
블록 내에서 예외가 발생하면 자바 가상 머신이 가장 먼저 인지한다. 이후 자바 가상 머신은 발생한 예외 타입의 객체를 생성해 catch(){}
블록의 매개변수로 전달한다. 이 예제에서처럼 만일 ArithmeticException이 발생하면 자바 가상 머신은 ArithmeticException 객체를 생성하고, 생성 객체를 catch(){}
블록의 매개변수로 전달하는 것이다. 이 과정은 마치 자바 가상 머신이 'catch()'라는 이름의 메서드를 호출하는 것과 비슷해 보인다. 만일 자바 가상 머신이 생성해 넘겨 준 객체 타입을 catch(){}
블록이 처리할 수 없을 때, 즉 해당 객체를 받을 catch(){}
블록이 존재하지 않을 때는 예외 처리가 되지 않아 프로그램이 강제 종료된다.
System.exit(정수)
는 현재 실행하고 있는 프로세스를 강제로 종료하는 System 클래스의 정적 메서드다. 매개변수로는 일반적으로 정상 종료일 때 0, 비정상 종료일 때 0 이외의 값을 사용한다.
14.2.3 다중 예외 처리
예외 처리 과정을 살펴보면 앞서 언급한 것처럼 마치 catch(){}
블록이 예외 클래스 타입을 입력매개변수로 갖는 메서드처럼 동작한다고 이해하면 꽤 잘 들어맞는다(물론 절대로 메서드는 아니다). 메서드가 다양한 입력매개변수 타입으로 오버로딩될 수 있는 것처럼 catch(){}
블록도 예외 타입에 따라 여러 개를 포함할 수 있다.
// 다중 예외 처리
try {
// ...
} catch (예외타입 e1) {
// ...
} catch (예외타입 e2) {
// ...
} ...
final {
// ...
}
이런 다중 예외 처리 구문을 작성할 때 반드시 주의해야 할 사항은 try{}
블록에서 예외가 발생하고, 여러 개의 catch(){}
블록이 있을 때 실행할 catch(){}
블록의 선택 과정은 항상 위에서부터 확인한다는 것이다. 이는 마치 if-else if-else 구문에서 조건식을 위에서부터 검사하는 것과 같다. 다음 예를 살펴보자.
2개의 catch(){}
블록이 있고, 첫 번째 블록에서는 Exception 타입, 두 번째 블록에서는 NumberFormatException 타입을 처리한다. 예외가 발생하면 항상 위에서부터 확인한다고 했으므로 제일 먼저 Exception 타입인지를 확인할 것이다. 그런데 모든 예외는 Exception 클래스의 하위 클래스이므로 어떤 예외가 발생하든 첫 번째 catch(){}
블록만 실행된다. 즉, 두 번째 catch(){}
블록은 절대 도달할 수 없는 코드(unreachable code)가 되므로 오류가 발생하는 것이다. 오류를 해결하려면 두 catch(){}
블록의 순서를 서로 바꾸면 된다.
다중 예외 처리 과정에서 각각의 예외가 발생했을 때 처리하는 내용이 동일할 수 있다. 이때는 굳이 catch(){}
블록을 따로 정의하고 동일한 코드를 중복하는 대신, 1개의 catch(){}
블록이 2개의 예외를 동시에 처리하도록 통합할 수 있다. 이때 각각의 예외 타입은 OR(I) 기호를 사용해 연결한다. 이렇게 되면 둘 중 어떤 예외가 발생하든 이 catch(){}
블록을 사용해 예외가 처리된다.
// 다중 예외를 한 블록에서 처리
try {
// ...
} catch (예외타입 A | 예외타입 B 참조변수명) {
// ...
} finally {
// ...
}
14.2.4 리소스 자동 해제 예외 처리
앞에서 finally{}
블록은 '항상 실행해야 하는 기능이 있을 때 사용하는 블록'이라고 했다. finally{}
블록의 가장 대표적인 기능은 리소스를 해제하는 것이다. 리소스 해제는 더이상 사용하지 않는 자원을 반납하는 것을 의미한다. 예를 들어 수정하기 위해 열어 둔 파일이 있다면 이 파일을 닫아야 다른 프로그램이 이 파일을 사용할 수 있다. 메모리에 엄청난 크기의 객체를 만들어 놓고 사용했을 때도 사용이 완료되면 메모리 공간을 확보하기 위해 리소스를 해제해야 할 것이다. 자바에서 리소스의 해제가 꼭 필요한 대표적인 예로 자바 입출력 리소스를 들 수 있다. 다음과 같이 예외 처리 구문을 사용해 try{}
블록에서 리소스를 사용하는 객체를 생성한 후 finally{}
블록에서 리소스를 해제하는 예외 처리 구문을 살펴보자.
InputStreamReader is = null;
try {
is = new InputStreamReader(System.in);
System.out.println(is.read());
} catch (IOException e) {
// 예외 처리
} finally {
if (is != null) {
try {
is.close();
} catch (Exception e) {
// 예외 처리
}
}
}
try{}
블록에서는 문자 단위로 입력을 수행하는 InputStreamReader 객체를 생성해 사용하고 finally{}
블록에서는 자원을 반납(is.close()
)했다. 자바 입출력을 아직 모르기 때문에 코드가 잘 이해되지 않겠지만, 'try{}
블록에서 객체를 생성하고 사용한 후 finally{}
블록에서 close()
메서드로 자원을 반납했다.' 정도는 이해할 수 있을 것이다. 대부분의 자바 입출력 코드는 이런 구조를 갖고 있다. 이런 반복적인 구조를 간략화하기 위해 추가된 예외 처리 구문이 리소스 자동 해제 예외 처리 구문이다.
// 리소스 자동 해제 예외 처리
try (리소스 자동 해제가 필요한 객체 생성) {
// 예외 발생 가능 코드
} catch (예외클래스명 참조변수명) {
// 해당 예외가 발생했을 때 처리하는 블록
} finally {
// 예외 발생 여부에 상관없이 무조건 실행하는 블록
}
기존 예외 처리 구문과의 유일한 차이점은 try(){}
구문에도 소괄호(()
)가 포함된다는 것이다. 이 소괄호 안에서 자동으로 리소스를 반납해야 할 객체를 생성하면 예외 처리 구문의 실행이 끝났을 때 리소스가 자동으로 해제된다. 좀 더 정확하게 말해, 예외 처리 구문이 완료되면 try(){}
블록의 소괄호 안에서 생성된 객체 내부의 close() 메서드를 자동으로 호출함으로써 리소스를 자동으로 해제한다. 즉, finally{}
블록에서 하던 일(객체가 null이 아니면 close() 메서드를 호출)을 자동으로 처리해 준다는 것이다. 다음 예제는 위의 예를 리소스 자동 해제 예외 처리 구문으로 변경한 것이다.
리소스를 자동으로 해제하기 위해서는 반드시 try(){}
블록의 소괄호 안에서 생성한 객체의 내부에 close() 메서드가 포함돼 있어야 한다. 이는 나중에 다시 다룬다.
try (InputStreamReader is = new InputStreamReader(System.in)) {
System.out.println(is.read());
} catch (IOException) {
// 예외 처리
}
이렇게 되면 리소스 자동 해제 예외 처리 구문을 빠져나갈 때 리소스 객체의 close() 메서드를 자동으로 호출해 리소스를 해제해 준다. 리소스가 정말 해제됐는지 확인하기 위해 다음 예제를 살펴보자.
그렇다면 모든 객체를 try(){}
블록의 소괄호 안에 넣을 수 있을까? 리소스 자동 해제 예외 처리 구문은 예외의 발생 여부와 관계없이 예외 처리 구문이 완료된 후 리소스 객체의 close()
메서드를 자동으로 호출해 준다고 했다. 따라서 리소스 객체 내부에 close()
메서드가 있어야 자동 해제를 할 수 있는 객체가 될 수 있을 것이다. 그렇다면 try(){}
구문 소괄호 안에서 생성된 객체 내부에 close()
메서드가 포함돼 있다는 것을 어떻게 보장할 수 있을까? 이것이 바로 AutoCloseable 인터페이스의 역할이다. 즉, 리소스 자동 해제를 위한 클래스는 반드시 이 AutoCloseable 인터페이스를 구현해야 한다. 이 인터페이스 내부에는 close() 추상 메서드가 포함돼 있기 때문에 이 인터페이스를 구현한 모든 클래스의 객체는 내부에 close() 메서드를 포함하고 있다는 것을 보장받을 수 있는 것이다. 다른 말로 이야기하면 AutoCloseable 인터페이스를 구현해 내부에 close() 메서드를 포함하고 있는 클래스의 객체에 한해서만 리소스 자동 해제 기능을 제공하겠다는 말이다.
다음 예제는 AutoCloseable 인터페이스를 구현한 후 close() 메서드의 내부에서 오버라이딩한 클래스를 정의한 예다. 여기서는 예외 처리 구문이 실행된 이후 close() 메서드가 호출된다는 것을 보이기 위해 내부에서는 필드를 null 값으로 초기화하고 "리소스 해제" 구문만 출력하는 코드만 작성해 놓았다. 여기서 throws Exception은 예외 전가 구문으로, 예외 처리를 자신을 호출한 지점으로 전가한다는 의미다. 이에 대해서는 다음 절에서 자세히 다룬다.
class A implements AutoCloseable {
String resource;
A (String resource) { this.resource = resource; }
@Override
public void close() throws Exception {
resource = null;
System.out.println("리소스 해제");
}
}
이제 리소스 자동 해제 예외 처리 구문을 이용해 다음과 같이 작성하면 명시적으로 close() 메서드의 호출 구문이 없는데도 "리소스 해제" 구문이 출력된다는 것을 알 수 있다.
try (A a = new A("특정 파일")) {}
catch (Exception) {} // "리소스 해제" 출력
14.3 예외 전가
예외가 발생했을 때 바로 처리할 수도 있지만, 자신을 호출한 지점으로 예외를 전가(throws)할 수도 있다. 예외 처리를 하지 않아 오류가 발생한 지점은 2가지 해결책이 있다. 하나는 앞에서 살펴본 try-catch 구문을 이용하는 것이고, 다른 하나는 예외를 전가하는 것이다. 예외를 전가하면 예외 처리의 의무를 호출한 메서드가 갖게 된다. 물론 상위의 메서드도 자신을 호출한 지점으로 예외를 전가할 수 있다.
14.3.1 예외 전가 문법
예외를 전가할 때는 메서드의 소괄호와 중괄호 사이에 전가시키고자 하는 예외 타입을 throws 키워드와 함께 삽입하는 방법을 사용한다.
// 예외 전가 구조
리턴타입 메서드명(입력매개변수) throws 예외클래스명 {
// 예외 발생 코드
}
그럼 abc() 메서드에서 bcd() 메서드를 호출하고, bcd() 메서드 내부에 예외가 발생할 수 있는 코드가 포함돼 있을 때를 살펴보자.
첫 번째는 bcd() 메서드가 직접 예외 처리를 했다. 이때는 abc() 메서드가 bcd()를 호출해 사용하는 데 아무런 문제가 발생하지 않는다. 반면 두 번째는 bcd() 메서드가 예외를 처리하지 않고, 자신을 호출한 메서드로 예외를 전가하고 있다. 이렇게 되면 이제 예외를 전가받은 abc() 메서드는 전가된 예외를 처리할 의무를 갖게 되는 것이다. 다시 말해 예외를 전가하고 있는 bcd() 메서드 자체가 예외 처리가 필요한 구문이 된 셈이다. 따라서 bcd() 메서드를 호출한 abc() 메서드에서 bcd()가 전가한 예외 클래스 타입에 대한 예외 처리 구문을 작성해야한다. 이제 실제 예를 이용해 알아보자.
void abc() {
try {
bcd();
} catch (InterruptedException e) {
// 예외 처리 구문
}
}
void bcd() throws InterruptedException {
Thread.sleep(1000);
}
이 예제에서는 2개의 메서드(abc(), bcd())가 있고, bcd() 메서드의 내부에는 예외 발생 가능 코드가 포함돼 있다. Thread.sleep(시간)에서는 일반 예외인 InterruptedException이 발생할 수 있기 때문에 해당 메서드를 사용하기 위해서는 반드시 예외 처리를 해 줘야 한다고 했다. 하지만 bcd() 메서드는 직접 예외 처리를 하는 대신, InterruptedException이 자신을 호출한 메서드로 전가했다. 즉, 예외 처리의 의무를 자신을 호출한 메서드로 전가한 것이다. 이렇게 되면 이제 abc() 메서드가 InterruptedException을 처리해 줘야 한다.
다시 처음으로 돌아가서 그동안 왜 Thread.sleep() 메서드를 사용하려면 예외 처리를 해 줘야 하는지에 대해 생각해 보자. 자바 API 문서에서 Thread.sleep() 메서드를 살펴보면 다음과 같이 InterruptedException을 전가하고 있는 것을 볼 수 있다. 다시 말해 실제 예외가 발생할 수 있는 구문은 Thread.sleep() 메서드 안에 포함돼 있었던 것이다. 그런데 이 메서드가 예외를 전가했으므로 어떤 메서드이든 Thread.sleep() 메서드를 호출하는 메서드가 예외 처리를 해야만 했던 것이다.
그렇다면 상위 메서드들도 예외를 직접 처리하지 않고 계속 전가만 한다면 어떤 일이 벌어질까? 다음 예시처럼 cde()부터 전가된 예외는 최상위 메서드인 main() 메서드까지 올라가고, main() 메서드마저도 예외를 전가하면 이 main() 메서드를 실행한 자바 가상 머신이 직접 예외를 처리하게 된다.
자바 가상 머신의 예외 처리 방식은 매우 간단명료하다. 발생한 예외의 정보를 화면에 출력하고 프로그램을 강제 종료하는 것이다. 앞에서 많이 본 상황이지 않은가? 그렇다. 만일 우리가 예외를 처리하지 않으면 그동안 자바 가상 머신이 혼자서 이런 식으로 예외를 처리해 왔던 것이다.
예외를 처리할 때 여러 개의 catch(){}
구문을 포함하는 다중 예외 처리가 가능했던 것처럼 하나의 메서드 안에 발생할 수 있는 예외가 여러 종류일 때는 여러 개의 예외를 한 번에 전가할 수 있다. 이때는 다음과 같이 쉼표(,)로 구분해 나열한다.
// 다중 예외 전가 구조
리턴타입 메서드명(입력매개변수) throws 예외클래스 A, 예외클래스 B, ... {
// 여러 개의 예외 종류가 발생할 수 있는 블록
}
14.4 사용자 정의 예외 클래스
사용자 정의 예외 클래스를 직접 작성하고 동작시켜 보면 이전에 다뤘던 자바에서 제공하는 다른 예외 클래스들의 동작 메커니즘도 자연스럽게 이해할 수 있을 것이다.
14.4.1 사용자 정의 예외 클래스 생성 방법
사용자 예외 클래스를 정의해 사용하는 과정은 크게 3단계로 이뤄져 있다. 첫 번째로 예외 클래스를 사용자가 직접 정의하고, 두 번째로 작성한 예외 클래스를 이용해 객체를 생성한다. 마지막으로는 고려하는 예외 상황에서 예외 객체를 던진다(throw).
사용자 정의 예외 클래스 작성 사용자 예외 클래스를 정의하는 방법은 자바에서 제공하는 예외 클래스와 마찬가지로 Exception을 바로 상속해 일반 예외 클래스로 만드는 방법과 RuntimeException을 상속해 실행 예외 클래스로 만드는 방법으로 나눌 수 있다. 사용자가 정의하는 예외라도 자바에서 제공하는 예외와 기본적인 특징은 같다. 사용자 클래스를 정의하는 과정에서 다음과 같이 기본 생성자와 문자열을 입력받는 생성자를 추가한다. 두 번째 생성자는 예외 메시지를 전달받아 예외 객체를 생성하는 생성자로, 내부에서는 부모 클래스인 Exception 또는 RuntimeException 클래스의 생성자를 호출해 사용한다.
사용자 정의 예외 객체 생성
이제 앞에서 정의한 예외 클래스로 예외 객체를 생성한다. 객체를 생성하는 방법은 일반 예외든, 실행 예외든 상관없이 일반 클래스로 객체를 생성하는 방법과 동일하다.
예외 상황에서 예외 객체 던지기
마지막으로 고려하는 예외 상황이 발생하면 생성한 객체를 던진다(throw). 예외 객체를 '던진다.'는 것은 '실제 자바 가상 머신에게 예외 객체를 만들어 전달한다.'는 의미다. 예외 객체를 던지면 곧바로 예외가 발생한다. 그러면 자바 가상 머신은 그 예외를 처리할 수 있는 catch(){} 블록에게 받았던 예외 객체를 전달할 것이다.
예외 객체를 전달할 때는 'throw 예외 객체'의 형식을 사용한다. 이때 사용하는 throw 키워드는 예외 객체를 던지는 기능을 수행하는 것으로, 예외를 전가하는 throws와 혼동할 수 있으므로 반드시 구분하길 바란다.
예외 객체를 throw 키워드로 던졌을 때 내부적으로 이뤄지는 처리 과정을 좀 더 자세하게 들여다보자. 던져진 예외 객체는 자바 가상 머신으로 전달되고, 자바 가상 머신은 해당 예외 객체를 처리할 catch(){}
블록을 찾는다. 따라서 throw 이후에 예외를 직접 처리하거나 예외를 전가하는 구문을 반드시 작성해야 한다. 해당 메서드가 직접 예외를 처리할 때는 자바 가상 머신이 전달받은 예외 객체를 해당 메서드 내의 예외 처리 블록으로 전달할 것이고, 예외를 전가했을 때는 예외 객체를 상위 메서드 내의 예외 처리 블록으로 전달할 것이다.
14.4.2 예외 클래스의 메서드
사용자 정의 예외 클래스는 Exception 또는 RuntimeException 클래스를 상속한다고 했다. 따라서 추가 메서드를 정의하지 않아도 부모 클래스의 메서드를 고스란히 내려받았을 것이다. 여기서는 그중 getMessage()와 printStackTrace() 메서드만 알아보자.
엄밀히 말하면 두 메서드는 Exception 클래스의 부모 클래스인 Throwable 클래스의 메서드다. 즉, 모든 Exception 클래스와 Error 클래스 내에서 사용할 수 있는 메서드라는 뜻이다.
getMessage() 메서드
getMessage()는 예외가 발생했을 때 생성자로 넘긴 메시지를 문자열 형태로 리턴하는 메서드로, 원형은 다음과 같다.
public String getMessage()
getMessage()는 객체를 생성했을 때 전달된 메시지를 리턴하는 메서드이므로 다음 예제와 같이 객체를 기본 생성자로 생성할 때 null 값을 리턴할 것이다.
// 예외 객체를 생성했을 때 메시지를 전달하지 않았을 경우
try {
throw new Exception();
} catch (Exception e) {
System.out.println(e.getMessage()); // null
}
반면 다음과 같이 문자열을 입력매개변수로 갖는 두 번째 생성자를 이용해 객체를 생성했을 때는 객체를 생성했을 때 넘겨 준 문자열을 리턴한다.
// 예외 객체를 생성했을 때 메시지를 전달했을 경우
try {
throw new Exception("예외 메시지");
} catch (Exception e) {
System.out.println(e.getMessage()); // 예외 메시지
}
printStackTrace() 메서드
printStackTrace()는 예외 발생이 전달되는 경로, 즉 예외가 전가된 과정을 한눈에 확인할 수 있는 메서드로, 원형은 다음과 같다.
public void printStackTrace()
'자바 > Do it! 자바 완전 정복' 카테고리의 다른 글
Do it! 자바 완전 정복: 13장 이너 클래스와 이너 인터페이스 (0) | 2025.01.31 |
---|---|
Do it! 자바 완전 정복: 12장 추상 클래스와 인터페이스 (1) | 2025.01.31 |
Do it! 자바 완전 정복: 11장 자바 제어자 2 (0) | 2025.01.31 |
Do it! 자바 완전 정복: 10장 클래스의 상속과 다형성 (0) | 2025.01.31 |
Do it! 자바 완전 정복: 9장 자바 제어자 1 (0) | 2025.01.31 |