공부/Java

[Java-08] 예외처리(Exception Handling)

줭♪(´▽`) 2021. 3. 4. 12:06

1. 예외처리(Exception Handling)

1) 프로그램 오류

- 프로그램 에러(오류) : 프로그램이 실행 중 어떤 원인에 의해서 오작동을 하거나 비정상적으로 종료되는 경우

 

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

런타임 에러는 '에러(error)'와 '예외(exception)'으로 구분
에러(error)        프로그램 코드에 의해서 수습될 수 없는 심각한 오류
예외(exception)  프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류

 

2) 예외 클래스의 계층구조

- 자바에서는 실행 시 발생할 수 있는 오류(Exception과 Error)를 클래스로 정의함

 

Exception과 Error도 Object클래스의 자손들임

 

Exception클래스와 RuntimeException클래스 중심의 상슥계층도

 

- 모든 예외의 최고 조상은 Exception클래스

- 예외 클래스는 두 그룹으로 나눔

 

Exception클래스들(Exception클래스와 그 자손들)
- 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외

RuntimeException클래스들(RuntimeException클래스와 그 자손들)
- 프로그래머의 실수로 발생하는 예외

 

3) 예외처리하기 (try-catch문)

 

예외처리(exception handilng)

① 정의 : 프로그램 실행 시 발생할 수 잇는 예외에 대비한 코드를 작성하는 것

② 목적 : 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것

 

try {
	// 예외가 발생할 가능성이 있는 문장들
} catch (Exception1 e1) {
	// Exception1이 발생했을 경우, 이를 처리하기 위한 문장
} catch (Exception2 e2) {
	// Exception2가 발생했을 경우, 이를 처리하기 위한 문장
} catch (ExceptionN eN) {
	// ExceptionN이 발생했을 경우, 이를 처리하기 위한 문장
}

 

- 하나의 try블럭 다음에는 하나 이상의 catch블럭이 올 수 있음

- 발생한 예외의 종류와 일치하는 단 한 개의 catch블럭만 수행됨

- 발생한 예외의 종류와 일치하는 catch블럭이 없으면 예외는 처리되지 않음

- { } 를 생략할 수 없음

 

try {
    try {  } catch (Exception e) {  }	// 가능
} catch (Exception e) {
    try {  } catch (Exception e) {  }	// 에러!! 변수 e가 중복 선언됨
}

- 중첩하여 try-catch문 사용 가능

- 단, 참조변수의 이름이 중복되면 안됨

 

 

4) try-catch문의 흐름

 

1. try블럭 내에서 예외가 발생한 경우
① 발생한 예외와 일치하는 catch블럭이 있는지 확인
② 일치하는 catch블럭을 찾으면 그 catch블럭 내의 문장들을 수행하고 전체 try-catch문을 빠져나가서 그 다음 문장을 계속해서 수행
③ 일치하는 catch블럭을 찾지 못하면 예외는 처리되지 못함

2. try블럭 내에서 예외가 발생하지 않은 경우
① catch블럭을 거치지 않고 전체 try-catch문을 빠져나가서 계속해서 수행

 

 

5) 예외의 발생과 catch블럭

- 예외가 발생하면 발생한 예외에 해당하는 클래스의 인스턴스가 만들어짐

- catch블럭을 차례로 내려가면서, instanceof연산자를 이용하여 인스턴스와 같은 catch블럭의 참조변수를 찾음

- 찾은 catch블럭을 수행

- 모든 예외 클래스는 Exception클래스의 자손이므로, Exception을 참조변수로 두면 어떤 종류의 예외가 발생하더라도 catch문이 실행됨

 

printStackTrace()  예외발생 당시의 호출스택(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 화면에 출력
getMessage()       발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있음

 

멀티 catch블럭

- JDK1.7부터 여러 catch블럭을 '|' 기호를 이용해서 하나의 catch블럭으로 합칠 수 있음
- 예외 클래스의 개수에는 제한이 없음
- 중복된 코드를 줄일 수 있음
- 단, 연결된 예외 클래스가 조상과 자손의 관계에 있으면 컴파일 에러 발생
- 단, 공통 분모인 조상 예외 클래스에 선언된 멤버만 사용 가능

 

try {
    ...
} catch (ExceptionA | ExceptionB | Exception c e) {
	e.printStackTrace();
}

 

 

6) 예외 발생시키기

- 키워드 throw를 사용해서 프로그래머가 고의로 예외를 발생시킬 수 있음

try {
    Exception e = new Exception("고의발생");
    throw e;
    // 또는 throw new Exception("고의발생");
} catch (Exception e) {
    ...
}

 

 

7) 메서드에 예외 선언하기

 

void method() throws Exception1, Exception2, ... ExceptionN {
    ....
}

 

- 메서드에 예외를 선언하면, 이 메서드를 사용하기 위해 어떠한 예외들이 처리되어야 하는지 쉽게 알 수 있음

- 자신을 호출한 메서드에게 예외를 전달하여 예외처리를 떠맡기는 것

- 호출스택에 있는 메서드들을 따라 전달되다가 제일 마지막에 있는 main메서드에서도 예외가 처리되지 않으면, main메서드마저 종료되어 프로그램 전체가 종료됨

- 따라서 어느 한 곳에서는 반드시 try-catch문으로 예외처리를 해주어야 함

 

8) finally 블럭

- 예외의 발생여부에 상관없이 실행되어야할 코드를 포함

try {
    // 예외가 발생할 가능성이 있는 문장들
} catch (Exception1 e1) {
    // 예외처리를 위한 문장들
} finally {
    // 예외의 발생여부와 관계없이 항상 수행되어야 하는 문장들
    // try-catch문의 맨 마지막에 위치
}

 

9) 자동 자원 반환 (try-with-resources문)

- JDK1.7부터 추가된 구문

- 입출력에 사용되는 클래스 중 사용한 후 꼭 닫아줘야 사용했던 자원이 반환되는 클래스가 있음

// 괄호 안에 두 문장 이상일 경우 ;로 구분
try (FileInputStream fis = new FileInputStream("score.dat");
	DataInputStream dis = new DataInputStream(fis)) {
    
    ...

} catch (EOFException e) {
    ...
} catch (IOException ie) {
    ...
}

- try-with-resources문을 사용하면 따로 close()를 호출하지 않아도 try블럭을 벗어나는 순간 자동적으로 close()가 호출

 

10) 사용자정의 예외 만들기

- 필요에 따라 새로운 예외 클래스를 정의하여 사용 가능

- 보통 Exception클래스 또는 RuntimeException클래스로부터 상속받아 사용

class MyException extends Exception {
    MyException(String msge) {
    	super(msg);
    }
}

 

11) 예외 되던지기(exception re-throwing)

- 한 메서드에서 발생할 수 있는 예외가 여럿인 경우, 예외가 발생한 메서드와 호출한 메서드 양쪽에서 처리하게 할 수 있음

- 예외가 발생한 메서드 : try-catch문을 사용하여 예외를 처리 후 throw문을 사용하여 예외를 다시 발생

- 호출한 메서드 : 전달받은 예외를 try-catch에서 또다시 처리

 

12) 연결된 예외(chained exception)

- 한 예외가 다른 예외를 발생시킬 수 있음

- 원인 예외(cause exception) : 예외를 발생시킨 원인이 되는 예외

- 여러가지 예외를 하나의 큰 분류의 예외로 묶어서 다루기 위해 원인 예외로 등록해서 다시 예외를 발생시킴

 

Throwable initCause (Throwable cause)  지정한 예외를 원인 예외로 등록
Throwable getCause()                          원인 예외를 반환

 

 

 

 

 

 

 

참고 - Java의 정석 3rd Edition (저자 : 남궁성, 출판 : 도우출판)