예외란 무엇인가요?

예외(exception)라는 용어는 “예외적인 이벤트”(exceptional event)라는 문구의 줄임말입니다.

정의: exception 는 프로그램 실행 중에 발생하는 이벤트로, 프로그램 명령어의 정상적인 흐름을 방해하는 것을 말합니다.

메서드 내에서 오류가 발생하면 메서드는 객체를 생성하여 런타임 시스템으로 넘깁니다. 예외 객체라고 하는 이 객체에는 오류의 타입과 오류가 발생했을 때의 프로그램 상태 등 오류에 대한 정보가 포함됩니다. 예외 객체를 생성하여 런타임 시스템에 전달하는 것을 예외를 던지기라고 합니다.

메서드가 예외를 던지면 런타임 시스템은 예외를 처리할 무언가를 찾으려고 시도합니다. 예외를 처리할 수 있는 ‘무언가’의 집합은 오류가 발생한 메서드에 도달하기 위해 호출된 메서드의 정렬된 목록입니다. 이러한 메서드 목록을 호출 스택이라고 합니다(다음 그림 참조).

The call stack

호출 스택

런타임 시스템은 호출 스택에서 예외를 처리할 수 있는 코드 블록이 포함된 메서드를 검색합니다. 이 코드 블록을 예외 처리기라고 합니다. 검색은 오류가 발생한 메서드부터 시작하여 메서드가 호출된 역순으로 호출 스택을 통해 진행됩니다. 적절한 처리기를 찾으면 런타임 시스템은 예외를 처리기로 전달합니다. 예외 처리기는 던져진 예외 객체의 타입이 처리기가 처리할 수 있는 타입과 일치하면 적절한 것으로 간주됩니다.

선택된 예외 처리기는 예외를 잡는다고(catch) 합니다. 다음 그림과 같이 런타임 시스템이 적절한 예외 처리기를 찾지 못한 채 호출 스택의 모든 메서드를 철저하게 검색하면 런타임 시스템(그리고 결과적으로 프로그램)이 종료됩니다.

Searching the call stack for the exception handler

호출 스택에서 예외 처리기 검색하기

예외를 사용하여 오류를 관리하면 기존의 오류 관리 기법에 비해 몇 가지 장점이 있습니다. 예외의 장점 섹션에서 자세히 알아볼 수 있습니다.

 

캐치 또는 지정 요건

유효한 Java 프로그래밍 언어 코드는 캐치 또는 지정 요구 사항 을 준수해야 합니다. 즉, 특정 예외를 발생시킬 수 있는 코드는 다음 중 하나로 묶어야 합니다:

  • 예외를 잡는 try 문. try는 예외 포착 및 처리에 설명된 대로 예외에 대한 핸들러를 제공해야 합니다.
  • 예외를 던질 수 있음을 지정하는 메서드. 메서드는 메서드가 던지는 예외 지정에 설명된 대로 예외를 나열하는 throws 절을 제공해야 합니다.

캐치 또는 지정 요구 사항을 준수하지 않는 코드는 컴파일되지 않습니다.

모든 예외에 Catch 또는 Specify 요건이 적용되는 것은 아닙니다. 그 이유를 이해하려면 세 가지 기본 예외 범주를 살펴볼 필요가 있으며, 그 중 하나만 요구 사항의 적용을 받습니다.

 

세 가지 종류의 예외

첫 번째 종류의 예외는 체크된 예외 입니다. 이는 잘 작성된 애플리케이션이 예상하고 복구해야 하는 예외적인 조건입니다. 예를 들어, 애플리케이션이 사용자에게 입력 파일 이름을 묻는 메시지를 표시한 다음 java.io.FileReader의 생성자에 이름을 전달하여 파일을 연다고 가정해 보겠습니다. 일반적으로 사용자는 읽을 수 있는 기존 파일의 이름을 제공하므로 FileReader 객체의 구성이 성공하고 애플리케이션 실행이 정상적으로 진행됩니다. 그러나 사용자가 존재하지 않는 파일의 이름을 제공하면 생성자가 java.io.FileNotFoundException을 던지는 경우도 있습니다. 잘 작성된 프로그램이라면 이 예외를 포착하여 사용자에게 실수를 알리고 파일 이름을 수정하라는 메시지를 표시할 것입니다.

체크된 예외는 캐치 또는 지정 요구사항의 적용을 받습니다. Error, RuntimeException 및 그 하위 클래스로 표시되는 예외를 제외한 모든 예외는 체크된 예외입니다.

두 번째 종류의 예외는 오류입니다. 이는 애플리케이션 외부에 있는 예외적인 조건으로, 애플리케이션이 일반적으로 예상하거나 복구할 수 없습니다. 예를 들어 애플리케이션이 입력을 위해 파일을 성공적으로 열었지만 하드웨어 또는 시스템 오작동으로 인해 파일을 읽을 수 없다고 가정해 보겠습니다. 읽기에 실패하면 java.io.IOError가 발생합니다. 애플리케이션은 사용자에게 문제를 알리기 위해 이 예외를 포착하도록 선택할 수도 있지만, 스택 추적을 인쇄하고 프로그램을 종료하는 것이 합리적일 수도 있습니다.

에러는 캐치 또는 지정 요구 사항의 적용을 받지 않습니다. 에러는 Error와 그 서브클래스가 나타내는 예외를 말합니다.

세 번째 종류의 예외는 런타임 예외입니다. 이는 애플리케이션 내부에 존재하는 예외적인 조건으로, 애플리케이션이 일반적으로 예상하거나 복구할 수 없습니다. 일반적으로 논리 오류나 부적절한 API 사용과 같은 프로그래밍 버그를 나타냅니다. 예를 들어, 앞서 설명한 애플리케이션이 FileReader의 생성자에 파일 이름을 전달한다고 가정해 보겠습니다. 논리 오류로 인해 생성자에 null이 전달되면 생성자는 NullPointerException을 던집니다. 애플리케이션에서 이 예외를 잡을 수는 있지만 예외를 발생시킨 버그를 제거하는 것이 더 합리적일 수 있습니다.

런타임 예외는 캐치 또는 지정 요구 사항의 적용을 받지 않습니다. 런타임 예외는 RuntimeException 및 그 서브클래스로 표시되는 예외입니다.

오류와 런타임 예외를 통칭하여 체크되지 않은 예외 라고 합니다.

 

캐치 또는 지정요건 우회하기

일부 프로그래머는 캐치 또는 지정 요구 사항을 예외 메커니즘의 심각한 결함으로 간주하고 체크된 예외 대신 체크되지 않은 예외를 사용하여 이를 우회합니다. 일반적으로 이는 권장되지 않습니다. 확인되지 않은 예외 - 논란에 대한 섹션에서 확인되지 않은 예외를 사용하는 것이 적절한 경우에 대해 설명합니다.