[Java] Exception

JeongYong Park·2023년 5월 20일
1

자바에는 다양한 예외가 존재하는데, 이번 포스팅에서는 자바의 예외에 대해서 작성해보고자 합니다.

예외(Exception)와 에러(Error)

예외에 대해 작성하기 전에 먼저 예외와 에러에 대해 작성하고자 합니다. 처음 프로그래밍을 공부할 때는 둘이 같은 것인 줄 알았던 적이 있었어서 먼저 둘의 차이를 작성하겠습니다.

  • 에러(Error)
    • 시스템, JVM에 비정상적인 상황이 발생했을 때를 의미합니다. 이는 시스템 수준에서 발생하기 때문에 개발자가 미리 예측해서 처리할 수 없다는 특징이 있습니다.
    • OutOfMemoryError, StackOverflowError 등이 존재합니다.
  • 예외(Exception)
    • 애플리케이션 수준에서 발생합니다. 그렇기 때문에 개발자가 미리 예측을 해서 처리할 수 있다는 특징이 있습니다.
    • NullPointerException, IOException 등이 존재합니다.

예외 처리

자바에서 메서드 호출 중에 예외가 발생하면 예외 인스턴스를 만들고 던지게(throwing) 됩니다. 메서드가 예외를 던지면 런타임 시스템에서는 이를 처리할 적절한 대상을 찾게 됩니다.

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

선택된 예외 처리기는 예외를 잡았다(catch)고 말합니다. 만약 런타임 시스템이 호출 스택의 모든 메서드를 순회하면서 적절한 예외 처리기를 찾지 못하면, 다음 그림과 같이 런타임 시스템(프로그램)이 종료됩니다.

CheckedException과 UncheckedException

자바에서는 예외를 크게 CheckedExceptionUncheckedException(RuntimeException)으로 구분해두었습니다.

CheckedException

CheckedException의 경우 메서드에 throws 키워드를 통해 명시적으로 던져주거나 try-catch 블럭을 통해 처리해주어야 하는 예외입니다.

public String read() throws IOException {	// 명시적으로 던져줌!
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    return br.readLine();
}

CheckedException의 경우 이러한 특성 때문에 예상가능하고 적절한 처리를 해야 하는 예외입니다.

UncheckedException (RuntimeException)

UncheckedException은 CheckedException과는 다르게 명시적인 예외처리(throws, try-catch)를 강요하지 않습니다.

UncheckedException은 애플리케이션 실행 중에 발생할 수 있는 예외이며, 예측할 수 없고 복구 가능하지 않은 예외입니다. 그래서 이런 예외는 일반적으로 프로그램 내의 논리적 오류나 부적절한 API의 사용을 나타냅니다.

예를 들어, 숫자를 0으로 나누거나 null 참조에 메서드를 호출하는 등의 경우입니다.

These are exceptional conditions that are external to the application, and that the application usually cannot anticipate or recover from.
https://docs.oracle.com/javase/tutorial/essential/exceptions/catchOrDeclare.html

왜 UncheckedException을 선호하는가?

CheckedException과 비교해 봤을 때 UncheckedException은 명시적인 예외처리를 할 필요가 없고 작성하기 쉬워보입니다.

CheckedExcpetion은 예외처리를 하지 않았다면 throws키워드를 통해 예외를 던져줍니다. 그러면 이 메서드를 사용하는 클라이언트 입장에서는 이 throws 자체가 API입니다. 즉, 해당 메서드를 사용하는 코드가 반드시 알아야하는 정보이기 때문에 이 API를 사용할 때 클라이언트는 적절한 처리를 수행할 수 있습니다.

그렇다면 UncheckedException은 왜 메서드에 throws 키워드를 선언하도록 강제하지 않을까요? (물론 이를 달아 해당 메서드가 어떤 예외를 던지는지 나타낼 수 있습니다.)
이는 API를 사용하는 클라이언트가 복구할 수 있는 방법이 없기 때문입니다. UncheckedException은 프로그램 전반에 걸쳐 어디서든 발생할 수 있는 예외입니다. 그래서 모든 메서드에 선언하도록 강제한다면 프로그램의 명확도는 떨어지게 될 것입니다. 그렇기 때문에 컴파일러는 UncheckedException을 적절히 처리하도록 강제하지 않습니다.

하지만 이러한 점이 예외를 던져줄 때 UncheckedException 을 선택하는 기준이 되어서는 안됩니다.

가이드라인 : 클라이언트가 해당 예외 상황을 복구할 수 있다면 checkedException을, 예외 상황이 발생했을 때 아무것도 할 수 없다면 uncheckedException을 사용합니다.

Here's the bottom line guideline: If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.

정리

  • Java에서 예외는 크게 CheckedException, UncheckedException으로 나뉜다.
  • CheckedException은 명시적인 예외처리를 필요로 하지만, UncheckedException은 그렇지 않다.
  • 그렇기 때문에 쉽게 사용하는 UncheckedException을 선택할 수 있지만 이는 잘못됐다. 기준을 가지고 예외를 처리하는 것이 좋다.

참고

https://docs.oracle.com/javase/tutorial/essential/exceptions/definition.html
https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html

profile
다음 단계를 고민하려고 노력하는 사람입니다

0개의 댓글