솜이의 데브로그

Chapter 08 ) 예외처리 본문

책을 읽자/Java의 정석

Chapter 08 ) 예외처리

somsoming 2021. 9. 10. 00:54

참고 : Java의 정석

 

1. 예외처리 (Exception handling)

 

에러의 종류

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

소스코드의 실행 과정은 다음과 같다.

소스코드(*.java) 에 대해 컴파일러가 오타나 잘못된 구문, 자료형 체크 등의 기본검사를 수행 → 클래스 파일 (*.class) 생성 →  생성된 클래스 파일 실행.

 

실행 시 (runtime) 발생할 수 있는 프로그램 오류는 에러와 예외 두가지로 구분한다.

  • 에러 : 프로그램 코드에 의해서 수습될 수 없는 심각한 오류. ex) 메모리 부족 (OutOfMemoryError), 스택오버플로우
  • 예외 (Exception) : 프로그램 코드에 의해 수습될 수 있는 다소 미약한 오류.

 

모든 예외의 최고 조상은 Exception 클래스이며, 상속 계층도를 Exception 클래스부터 도식화하면 두 그룹으로 나눌 수 있다.

  • Exception 클래스와 그 자손들 : 사용자의 실수 같은 외적 요인에 의해 발생하는 예외
  • RuntimeException클래스와 그 자손들 : 프로그래머의 실수로 발생하는 예외

 

예외처리란, 프로그램 실행 시 발생할 수 있는 예기치 못한 예외의 발생에 대비한 코드를 작성하는 것이다.

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

 

try{
	// 예외 발생 가능성이 있는 문장
} catch (Exception1 e1) {
	//Exception1이 발생했을 경우 처리
} catch (Exception2 e2){
	//Exception2가 발생했을 경우 처리
} catch (ExceptionN eN){
	// ExceptionN이 발생했을 경우 처리
}

하나의 try 블럭에 여러종류의 예외를 처리할 수 있도록 하나 이상의 catch 블럭이 올 수 있으며, 발생한 예외 종류와 일치하는 단 하나의 catch 블럭만 수행된다.

 

try-catch 문에서의 흐름

예외가 발생한 경우와 발생하지 않았을 때의 흐름이 달라진다.

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

 

catch 블럭은 ()와 {} 두부분으로 나누어져 있는데, 괄호() 내에는 처리하고자 하는 예외와 같은 타입의 참조변수를 선언해야한다.

예외클래스의 인스턴스에 instance 연산자를 이용해서 검사하게 된다.

 

예외에 대한 정보

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

이처럼 try-catch 문으로 비정상적으로 종료하지 않도록 하는 동시에 예외의 발생원인을 알 수 있다.

 

 

멀티 catch 블럭 : '|' 기호를 이용해 하나의 catch 블럭을 합칠 수 있게 되었다. (JDK1.7부터)

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

 

예외 발생시키기

키워드 throw를 사용해 고의로 예외를 발생시킬 수 있다.

  1. 연산자 new를 이용해 발생시키려는 예외 클래스의 객체를 만든다.   ex) Exception e = new Exception("고의로 발생시켰음");
  2. 키워드 throw를 용해 예외를 발생시킨다.   ex) throw e;

 

메서드에 예외 선언하기

메서드의 선언부에 키워드 throws를 사용해 메서드 내에서 발생할 수 있는 예외를 적어주면 된다.

ex)

void method() throws Exception1, Exception2, ... ExceptionN{
	//메서드 내용
}

 

이렇게 예외를 선언하면 이 예외 뿐만 아니라 그 자손타입의 예외까지도 발생할 수 있다.

메서드에 예외를 선언 할 때 일반적으로 RuntimeException 클래스들은 적지 않는다. 

 

 Java API 문서를 통해 사용하고자하는 메서드의 선언부와 'Throws:'를 보고 예외처리를 해주는 것이 좋다.

 

 

Finally 블럭

finally 는 예외의 발생여부에 관계 없이 코드를 수행하도록 한다.

 

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

 

예외가 발생한 경우 try catch finally 순으로 실행, 예외가 발생하지 않은 경우 try finally 순으로 실행. 

 

try-with-resources 문

 

사용자 정의 예외 생성 가능. Exception 클래스 상속받아서.

예외처리를 선택적으로 할 수 있도록 RuntimeException을 상속받아서 작성하는 쪽으로 바뀌어가고있다.

 

 

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

예외를 메서드 내에서 자체적으로 처리하고 나머지는 선언부에 지정하여 호출한 메서드에서 처리하도록 함.

catch문에서 필요한 작업을 행한 후에 throw문을 사용해서 예외를 다시 발생시킨다.

 

연결된 예외 (chained exception)

한 예외가 다른 예외를 발생시킬 수 있다. 예외 A가 예외B를 발생시켰다면, A를 B의 '원인 예외' 라고 한다.

 

연결 예외 어렵다ㅠㅠ