예외처리
프로그램 오류
- 컴파일 에러 : 컴파일 시에 발생하는 에러
- 런타임 에러 : 실행 시에 발생하는 에러
- 논리적 에러 : 실행은 되지만, 의도와 다르게 동작하는 것
자바에서는 실행시 발생할 수 있는 프로그램 오류를 에러와 예외(exception)로 구분
- 에러 : 메모리 부족이나 스택오버플로우처럼 일단 발생하면 복구할 수 없는 심각한 오류
- 예외 : 발생하더라도 수습될 수 있는 비교적 덜 심각한 것. 프로그램 코드에 의해서 수습될 수 있는 오류
예외 클래스의 계층 구조
자바에서는 실행시 발생할 수 있는 오류(Exception, Error)를 클래스로 정의 모든 클래스의 조상은 Object 클래스 -> Exception과 Error 또한 Object클래스의 자손
예외 클래스의 두 종류
- Exception 클래스와 그 자손들
- RuntimeException 클래스와 그 자손들
RuntimeException Class
주로 프로그래머의 실수에 의해서 발생될 수 있는 예외들
- ArrayIndexOutOfBounds : 배열의 범위를 벗어남
- NullPointerException : 값이 null인 참조변수의 멤버를 호출하려 함
- ClassCastException : 클래스간의 형변환을 잘못함
- ArithmeticException : 정수를 0으로 나누려고 함 등등…
Exception Class
주로 외부의 영향으로 발생할 수 있는 것. 프로그램의 사용자들의 동작에 의해서 발생하는 경우가 많음
- FileNotFoundException : 존재하지 않는 파일의 이름을 입력함
- ClassNotFoundException : 클래스 이름을 잘못 적음
- DataFormatException : 입력한 데이터 형식이 잘못됨 등등 …
예외처리하기 : try - catch 문
- 예외처리 : 프로그램 실행시 발생할 수 있는 예기치 못한 예외의 발생에 대비한 코드를 작성하는 것.
- 프로그램의 비정상적인 종료를 막고, 정상적인 실행상태를 유지하기 위함이다.
1
2
3
4
5
6
7
try {
//예외가 발생할 가능성이 있는 문장
} catch (Exception e1) {
//Exception 처리 문장
} catch (Exception e2) {
//Exception2 처리 문장
} //계속해서 Exception처리 가능
- 발생한 예외와 일치하는 catch블럭이 있는지 확인한다
- 일치하는 catch블럭을 찾게 되면, 그 catch블럭 내의 문장들을 수행, 전체 catch문을 빠져나가서 그 다음 문장을 계속해서 수행
- 만일 일치하는 catch블럭을 찾지 못하면 예외는 처리되지 못함.
- 예외 발생하지 않은 경우, catch블럭을 거치지 않음
예외 메시지 받기
printStackTrace()
예외 발생 당시 호출 스택에 있었던 메소드의 정보와 예외 메세지를 화면에 출력한다.
getMessage()
발생한 예외클래스의 인스턴스에 저장된 메세지를 얻을 수 있다.
위 두가지 에러 메세지 출력으로 프로그램을 정상적으로 종료시키면서 예외의 발생 원인을 알아낼 수 있음
Multi catch block
JDK1.7부터 여러 catch블럭을 |
를 이용해서 하나의 catch블럭으로 합칠 수 있게 됨
1
2
3
4
5
try {
} catch (ExceptionA | ExceptionB e) {
e.printStackTrace();
}
만약 ExceptionA 와 ExceptionB가 조상과 자손의 관계라면 컴파일 에러 발생. 왜냐면 조상 클래스에만 써주는 것과 동일한 결과이기 때문에 불필요한 코드를 제거하라는 의미에서 에러가 발생하는 것.
- 멀티 catch는 하나의 catch블럭으로 여러가지 예외를 처리해서, 실제로 어떤 예외가 발생한 것인지 알기 어려움.
- 참조변수 e로 멀티 catch블럭에
|
기호로 연결된 예외 클래스들의 공통 분모인 조상 예외 클래스에 선언된 멤버만 사용할 수 있음.
예외 발생시키기
-
연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 만듦
Exception e = new Exception("예외 발생");
-
키워드 throw를 이용해서 예외를 발생시킴
throw e;
1
2
3
4
5
6
7
8
9
10
11
12
13
class Exception1 {
public static void main(String args[]) {
try {
Exception e = new Exception("예외 발생");
throw e;
//throw new Exception("예외 발생"); 두 줄을 한 줄로 줄일 수 있음
} catch (Exception e) {
System.out.println("에러 메세지 : " + e.getMessage());
e.printStackTrace();
}
System.out.println("프로그램 정상 종료")
}
}
Exception인스턴스 생성시, 생성자에 String을 넣어주면 Exception이 인스턴스에 메세지로 저장됨. getMessage()로 메세지를 얻을 수 있음.
메소드에 예외 선언하기
예외를 처리하는 방법 1. try-catch문, 2. 예외를 메소드에 선언
1
2
3
void method() throws Exception1, Exception2, ... ExceptionN {
//메소드 내용
}
1
2
3
void method() throws Exception {
//메소드 내용
}
모든 예외의 최고 조상인 Exception클래스를 메소드에 선언하면, 모든 종류의 예외가 발생할 가능성이 있다는 뜻. -> 이 예외뿐 아니라 자손 타입의 예외까지 발생할 수 있음.
-
기존의 다른 언어들은 메소드에 예외 선언을 하지 않기 때문에, 어떤 상황에서 어떤 종류의 예외가 발생할 가능성이 있는지 충분히 대비하기 힘들었음.
-
자바는 메소드에서 발생할 가능성이 이는 예외를 선언부에 명시할 수 있기 때문에 견고한 프로그램 코드를 짤 수 있게 도와줌.
-
예외를 메소드의 throws에 명시하는 것은 예외를 처리하는 것이 아니라 해당 메소드를 호출한 메소드에게 예외를 전달하여 예외 처리를 하게 하는 것.
finally 블럭
- try-catch 문과 함께 예외의 발생여부에 상관없이 실행되어야 할 코드를 포함시킬 목적으로 사용됨
사용자 정의 예외
- 컴파일러가 체크하는 일반 예외로 선언할 수 있다. (
Exception
상속) - 컴파일러가 체크하지 않는 실행 예외로 선언할 수도 있다. (
RuntimeException
상속)
1
2
3
4
public class XXXException extends [Exception | RuntimeException] {
public XXXException() { }
public XXXException(String message) { super(message); }
}
- 사용자 예외 클래스의 이름은
Exception
으로 끝나는 것이 좋다. - 사용자 정의 예외 클래스도 필드, 생성자, 메소드 선언들을 포함할 수 있지만 대부분 생성자 선언만을 포함한다.
- 생성자는 두 개를 선언하는 것이 일반적
- 기본 생성자 (매개 변수 없는)
- String 타입의 매개 변수를 갖는 생성자 (에러 메시지를 전달하기 위해)
- 상위 클래스의 생성자를 호출하여 예외 메시지를 넘겨준다.
- 예외 메시지의 용도 : catch{}블록의 예외 처리 코드에서 이용하기 위함
1
2
3
public void method() throws XXXException {
throw new XXXException("메시지");
}
1
2
3
4
5
6
7
8
9
10
11
try {
method();
} catch (XXXException e) {
//예외 처리
// 예외가 가지고 있는 메시지 얻기
String message = e.getMessage();
// 예외의 발생 경로 추적
e.printStackTrace();
}