[자바의정석]Chapter 08. 예외처리(Exception Handling)

seungwon·2023년 1월 11일
0

자바의 정석

목록 보기
8/14

1. 예외처리(exception handling)

1.1 프로그램 오류

  • 컴파일 에러 : 컴파일 시에 발생하는 에러

  • 런타임 에러 : 실행 시에 발생하는 에러

    • 에러(error) : 프로그램 코드에 의해서 수습될 수 없는 심각한 오류
    • 예외 (exception) 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류
      • checked 예외 : 컴파일러가 예외처리를 확인하는 Exception 클래스들
      • unchecked 예외 : 컴파일러가 예외처리를 확인하지 않는 RuntimeException 클래스들
  • 논리적 에러 : 실행은 되지만, 의도와 다르게 동작하는 것

1.2 예외 클래스의 계층 구조

Exception과 Error를 클래스로 정의한 것


RuntimeException : 주로 프로그래머의 실수에 의해서 발생될 수 있는 예외들로 자바의 프로그래밍 요소들과 관계가 깊음

ex)배열의 범위를 벗어난다던가(ArraylndexOutOfBoundsException), 값이 null인 참조변수의 멤버를 호줄하려 했다던가 (NullPointerException), 클래스간의 형변환을 잘못했다던가(ClassCastException), 정수를 0으로 나누려고(ArithmeticException)하는 경우

1.3 예외처리 : try-catch 문

예외처리 (exception handling) 의
\quad정의 - 프로그램 실행 시 발생할 수 있는 예외에 대비한 코드를 작성하는 것
\quad목적 - 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것

try { // 중괄호({}) 생략 불가능
	// 예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch (Exceptionl el) {
	// Exception1이 발생했을 경우,이를 처리하기 위한 문장을 적는다.
} catch (Exception2 e2) {
	// Exception2이 발생했을 경우,이를 처리하기 위한 문장을 적는다.
} catch (ExceptionN eN) {
	//ExceptionN이 발생했을 경우,이를 처리하기 위한 문장을 적는다.
}

이 중 발생한 예외의 종류와 일치하는 단 한 개의 catch블럭만 수행되고 발생한 예외의 종류와 일치하는 catch블럭이 없으면 예외는 처리되지 않음

  • 모든 catch블럭에 참조변수 'e' 하나만을 사용해도 됨(∵ catch블럭의 괄호 내에 선언된 변수는 catch블럭 내에서만 유효)
    • catch블럭 내에 또 하나의 try-catch문이 포함된 경우,같은 이름의 참조변수를 사용해서는 안 됨

1.4 try-catch문에서의 흐름

  • try블럭 내에서 예외가 발생한 경우,

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

    1. catch블릭을 거치지 않고 전체 try- catch문을 빠져나가서 수행을 계속한다.

1.5 예외의 발생과 catch블럭

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

-> catch블럭부터 차례로 내려가면서 catch블럭의 괄호()내에 선언된 참조변수의 종류와 생성된 예외클래스의 인스턴스에 instanceof 연산자를 이용해서 검사

모든 예외 클래스는 Exception클래스의 자손
-> catch블럭의 괄호()에 Exception클래스 타입의 참조변수를 선언해 놓으면 어떤 종류의 예외가 발생하더라도 이 catch블럭에 의해서 처리된다.

-> try-catch문의 마지막에 Exception클래스 타입의 참조변수를 선언한 catch블럭을 사용하면, 어떤 종류의 예외가 발생하더라도 이 catch블럭에 의해 처리되도록 할 수 있다.

관련 메서드

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

멀티 catch블럭

여러 catch블릭을 ‘|’기호로 합친 것

try {
	...
} catch (ExceptionA | ExceptionB e) {
	e.printstackTrace();
}
  • 조상-자손 관계의 예외클래스를 '|'로 연결시 에러 : 조상클래스만 써주면 됨
  • 멀티 catch블럭 내에 예외 클래스들의 공통 분모인 조상 예외 클래스에 선언된 멤버만 사용할 수 있음
try {
	...
} catch (ExceptionA | ExceptionB e) {
	e.methodA();// 에러.ExceptionA에 선언된 methodA()는호출불가
    ...

1.6 예외 발생시키기 : throw

  1. 연산자 new -> 예외 클래스 객체 생성
    ex) Exception e = newException("테스트");
  • Exception 인스턴스 생성시 생성자에 String(ex."테스트")를 넣어주면getMessage()를 이용해 얻을 수 있음
  1. 키워드 throw를 이용해서 예외 발생시킴
    throw e;

1.7 예외 처리하기 : 메서드에 예외 선언하기(throws)

예외를 발생시키는 키워드 : throw
예외를 메서드에 선언 : throws

void method() throws Exception1, Exception2, ... Exceptions { 
	// 메서드의 내용
}
  • 이 메서드가 해당 예외 & 자손타입의 예외를 발생시키를 수 있음
    • 보통 반드시 처리해야하는 Exception 클래스의 자손들만 표시(<-> RuntimeException 클래스)
  • 메서드의 선언부에 예외 선언 -> 이 메서드를 사용하기 위해 어떤 예외를 처리되야 하는지 파악 가능
    • 예외를 처리하기 보다는 자신을 호출한 메서드에게 예외처리를 떠맡기는 것 -> 어느 한 곳에서는 반드시 try-catch문으로 예외처리

1.8 finally 블럭

예외의 발생여부에 상관없이 실행되어야할 코드를 포함시킬 목적으로 사용
(try블럭에서 return문을 만나도 finally 블럭의 문장은 수행함)

try-catch-finally

1.9 자동 자원 반환 : try-with-resources 문

주로 입출력(I/O)과 관련된 클래스를 사용할 때 유용 : 사용한 후에 꼭 닫아서 자원을 반환해야 하는 경우

try {
	fis = new FileInputStream(nscore.dat"); 
    dis = new DatalnputStream(fis);
} catch (IOException ie) { 
	ie.printStackTrace();
} finally {
	try {
		if (dis! =null)
			dis.close(); 
    } catch(IOException ie){
		ie.printstackTrace(;
	}
}

🚨 finally 블럭 안에 try-catch 문
:코드가 복잡, try블럭과 finally블럭에서 모두 예외가 발생하면 try블럭의 예외는 무시됨

=> try-with-resources문 : try-with-resources문의 괄호()안에 객체를 생성

try(객체 생성 코드){ 
	...
} catch (exception){
	...
  • 따로 close()를 호출하지 않아도 try블력을 벗어나는 순간 자동적으로 close()가 호출됨
    (그 이후에 catch/finally 블럭이 수행됨)
  • 제약 사항 : 클래스가 AutoCloseable 인터페이스를 구현
  • try블럭과 자동 호출되는 close()에서 예외 발생시 : 두개 모두 발생, close()문의 예외는 suppressed(억제된) 예외로 출력됨
  • 억제된(suppressed) 예외 관련 메소드
    void addSuppressed (Throwable exception) : 억제된 예외를 추가
    Throwable[] getSuppressed() : 억제된 예외 (배열)를 반환

1.10 사용자정의 예외 만들기

  • Exception / RuntimeExcpetion 클래스로부터 상속받아 클래스 만들기
  • 필요에 따라서 알맞은 예외 클래스를 선택
  • 기존 : 주로 Exception을 상속받아서 checked 예외(처리를 강제)로 작성하는 경우가 많았음
  • 최근 : 필요에 따라 예외처리의 여부를 선택할 수 있는 unchecked 예외 선호

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

예외를 처리한 후에 인위적으로 다시 발생시키는 방법

-> 예외가 발생한 메서드와 호출한 메서드 양쪽에서 처리할 수 있도록 함
(양쪽 모두 에서 처리해줘야 할 작업이 있을 때 사용)

1.12 연결된 예외(chained exception)

한 예외가 다른 예외를 발생시키는 경우

ex. 예외 A -> 예외 B 발생 : A를 B의 '원인 예외(cause exception)' 이라고 함

관련 메서드

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

사용 이유

  • 여러가지 예외를 하나의 큰 분류의 예외로 묶어서 다루기 위해서
  • checked예외를 unchecked예외로 바꿀 수 있도록 하기 위해서
static void startlnstall() throws SpaceException, MemoryException {
	if(!enoughSpace()) // 충분한 설치 공간이 없으면...
		throw new SpaceException("설치할 공간이 부족합니다.");
	if (!enoughMemory()) // 충분한 메모리가 없으면... 
    	throw new MemoryException(’’메모리가 부족합니다.");
}

⬇️

static void startlnstall() throws SpaceException{
	if(!enoughSpace()) // 충분한 설치 공간이 없으면...
		throw new SpaceException("설치할 공간이 부족합니다.");
	if (!enoughMemory()) // 충분한 메모리가 없으면... 
    	throw new RuntimeException(new MemoryException(’’메모리가 부족합니다."));
        // RuntimeException (Throwable cause) : 원인 예외를 등록하는 생성자
}

RuntimeException으로 감싸버렸기 때문에 unchecked예외가 된 것
-> 더 이상 startlnstall()의 선언부에 MemoryException을 선언하지 않아도 됨

0개의 댓글