Java - 예외처리

exception handling

Posted by Yan on March 22, 2021

예외처리

프로그램 오류

  1. 컴파일 에러 : 컴파일 시에 발생하는 에러
  2. 런타임 에러 : 실행 시에 발생하는 에러
  3. 논리적 에러 : 실행은 되지만, 의도와 다르게 동작하는 것

자바에서는 실행시 발생할 수 있는 프로그램 오류를 에러와 예외(exception)로 구분

  • 에러 : 메모리 부족이나 스택오버플로우처럼 일단 발생하면 복구할 수 없는 심각한 오류
  • 예외 : 발생하더라도 수습될 수 있는 비교적 덜 심각한 것. 프로그램 코드에 의해서 수습될 수 있는 오류

예외 클래스의 계층 구조

자바에서는 실행시 발생할 수 있는 오류(Exception, Error)를 클래스로 정의 모든 클래스의 조상은 Object 클래스 -> Exception과 Error 또한 Object클래스의 자손

예외 클래스의 두 종류

  1. Exception 클래스와 그 자손들
  2. RuntimeException 클래스와 그 자손들
RuntimeException Class

주로 프로그래머의 실수에 의해서 발생될 수 있는 예외들

  1. ArrayIndexOutOfBounds : 배열의 범위를 벗어남
  2. NullPointerException : 값이 null인 참조변수의 멤버를 호출하려 함
  3. ClassCastException : 클래스간의 형변환을 잘못함
  4. ArithmeticException : 정수를 0으로 나누려고 함 등등…
Exception Class

주로 외부의 영향으로 발생할 수 있는 것. 프로그램의 사용자들의 동작에 의해서 발생하는 경우가 많음

  1. FileNotFoundException : 존재하지 않는 파일의 이름을 입력함
  2. ClassNotFoundException : 클래스 이름을 잘못 적음
  3. DataFormatException : 입력한 데이터 형식이 잘못됨 등등 …

예외처리하기 : try - catch 문

  • 예외처리 : 프로그램 실행시 발생할 수 있는 예기치 못한 예외의 발생에 대비한 코드를 작성하는 것.
  • 프로그램의 비정상적인 종료를 막고, 정상적인 실행상태를 유지하기 위함이다.
1
2
3
4
5
6
7
try {
    //예외가 발생할 가능성이 있는 문장
} catch (Exception e1) {
    //Exception 처리 문장
} catch (Exception e2) {
    //Exception2 처리 문장
} //계속해서 Exception처리 가능
  1. 발생한 예외와 일치하는 catch블럭이 있는지 확인한다
  2. 일치하는 catch블럭을 찾게 되면, 그 catch블럭 내의 문장들을 수행, 전체 catch문을 빠져나가서 그 다음 문장을 계속해서 수행
  3. 만일 일치하는 catch블럭을 찾지 못하면 예외는 처리되지 못함.
  4. 예외 발생하지 않은 경우, 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블럭에 | 기호로 연결된 예외 클래스들의 공통 분모인 조상 예외 클래스에 선언된 멤버만 사용할 수 있음.

예외 발생시키기

  1. 연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 만듦

    Exception e = new Exception("예외 발생");

  2. 키워드 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으로 끝나는 것이 좋다.
  • 사용자 정의 예외 클래스도 필드, 생성자, 메소드 선언들을 포함할 수 있지만 대부분 생성자 선언만을 포함한다.
  • 생성자는 두 개를 선언하는 것이 일반적
    1. 기본 생성자 (매개 변수 없는)
    2. 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(); 
}