예외처리 란 프로그램의 비정상적인 종료를 방지하고 정상적인 실행상태를 유지하기 위한 처리를 말한다.
발생 시점에 따라 컴파일 에러, 런타임 에러로 나눈다.
컴파일 할 때 발생하는 에러.
주로 오타, 문법적 오류로 인해 발생한다.
실행 시에 발생하는 에러
실행 시 발생할 수 있는 프로그램 오류를 에러와 예외 두 가지로 구분한다.
- 에러: 복구하기 어려운 수준의 심각한 오류(메모리 부족, 스택오버플로우 등)
- 예외: 코드 수정 등을 통해 수습이 가능한 오류
실행 시 발생할 수 있는 오류가 클래스(Exception
, Error
)로 정의되어 있다.
모든 예외와 에러 클래스는 Throwable
클래스로부터 확장되고 모든 예외의 최고 조상은 Exception
클래스다.
예외 클래스는 두 그룹으로 나눌 수 있다.
RuntimeException
클래스와 그 하위 클래스를 제외한 모든 Exception
클래스와 그 하위 클래스들.
컴파일러가 실행 전에 예외 처리를 확인하기 때문에 checked 예외 라고 부른다.
프로그램 사용자의 실수로 발생하는 경우가 많다.
RuntimeException
클래스와 그 하위클래스들.
컴파일러가 예외 처리 코드 여부를 검사하지 않기 때문에 unchecked 예외 라고 부른다.
개발자의 실수로 발생하는 경우가 많다.
예외가 발생할 가능성이 있는 코드들을 try 블럭 에 작성하며, 발생한 예외를 처리하는 코드들을 catch 블럭 에 작성한다.
catch 블럭 은 여러 개 작성할 수 있으며, 발생한 예외의 종류와 일치하는 catch 블럭 하나만 실행된다.
- try 블럭 에서 예외가 발생한 경우
예외가 발생하면 발생한 예외에 해당하는 클래스의 인스턴스가 생성된다.
발생한 예외 종류와 일치하는 catch 블럭 을 찾아서(instanceof 연산자를 통해 검사) 실행하고, 이후 전체 try-catch 문 을 빠져나가고 다음 문장들을 실행한다.
일치하는 catch 블럭 을 찾지 못하면 예외는 처리되지 못한다.
- try 블럭 에서 예외가 발생하지 않은 경우, catch 블럭 은 실행되지 않고 try-catch 문 을 빠져나가 다음 문장들을 실행한다.
발생한 예외를 처리하지 못하면 프로그램은 비정상 종료되고, 처리되지 못한 예외(uncaught exception) 은 JVM의 예외처리기(UncauthExceptionhandler) 가 받아서 예외 원인을 화면에 출력한다.
finally 블럭 은 예외 발생 여부와 상관없이 무조건 실행된다.
예외가 발생했을 때 생성되는 예외 인스턴스는 발생한 예외에 대한 정보가 담겨 있다.
여러 catch 블럭 을 |
기호를 사용하여 하나의 catch 블럭 으로 합칠 수 있다.
try {
...
} catch (ExceptionA | ExceptionB e) {
...
}
연결된 예외 클래스가 조상과 자손의 관계라면 컴파일 에러가 발생한다.
throw
키워드를 사용하여 예외를 발생시킬 수 있다.
Exception e = new Exception("의도적으로 발생시킨 에외");
throw e;
//혹은
throw new Exception();
Exception
인스턴스를 생성할 때, 생성자에 String을 인자로 전달해 예외 메세지를 저장할 수 있다.
메서드 선언부에 throws
키워드를 사용하여 메서드 내에서 발생할 수 있는 예외를 적어준다.
여러 예외가 발생한다면 ,로 구분해서 여러 개의 예외를 선언할 수 있다.
void method() throws Exception {
...
}
위와 같이 예외를 선언하면 Exception
클래스는 모든 예외 클래스의 상위 클래스이기 때문에 하위 클래스 타입의 예외 클래스들이 모두 포함된다.
메서드의 선언부에 예외를 선언하는 것은 해당 메서드(예외가 발생할 수 있는 메서드)를 호출하는 메서드에게 예외를 전달하여 예외 처리를 떠맡기는 것이다.
Exception
클래스 또는 RuntimeException
클래스를 상속하여 사용자 정의 예외 클래스를 만든다.
class MyException extends Exception {
private final int ERR_CODE;
MyException(String msg, int errCode) {
super(msg); // 조상인 Exception클래스의 생성자를 호출
ERR_CODE = errCode;
}
}
Exception
클래스를 상속 하면 checked 예외 로 반드시 예외 처리를 해야 하지만, RuntimeException
클래스를 상속 하면 unchecked 예외 로 예외 처리를 선택적으로 할 수 있다.
예외가 발생할 가능성이 있는 메서드에서 try-catch 문 을 사용해서 예외를 처리하고, catch 블럭 에서 throw
키워드를 사용하여 예외를 다시 발생시켜 이 메서드를 호출한 메서드에게 예외를 넘겨 호출한 메서드에서도 예외를 처리하도록 하는 방법이다.
try-catch 문을 사용해서 예외를 처리함과 동시에 메서드 선언부에 발생할 예외를 선언해주어야 한다.
예외 A가 예외 B를 발생시켰다면, A를 B의 원인 예외 라고 한다.
initCause()
메서드의 인자로 특정 예외를 전달하여 원인 예외로 등록할 수 있다.
Exception
클래스의 조상인 Throwable
클래스에 정의되어 있기 때문에 모든 예외에서 사용 가능하다.
Throwable initCause(Throwable cause) //지정한 예외를 원인 예외로 등록
Throwable getCause() // 원인 예외를 반환
여러가지 예외를 하나의 큰 예외로 묶어서 다루기 위해서 예외를 연결하기 위해서다.