이펙티브 자바 스터디를 하다가 Exception에 대해 자세히 알 기회가 생겼는데, 평소에는 몰랐던 부분이기도 하고 알고 나니까 신기해서 간단하게 정리해보려고 한다.
1. Exception 이란?
자바 개발을 하면서 모르면 안 되는 개념이지만, 막상 정의를 하려니 어떻게 말해야 명료하게 느껴질지 모르겠다.
"프로그램에서 발생한 오류를 java에서는 Exception이라고 한다"는 말이 가장 먼저 떠오르는데, 이렇게 답하자니 뭔가 부족한 설명으로 느껴진다.
오라클에 있는 자바 자습서에 따르면 예외의 정의는 아래와 같다.
Definition: An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions.
즉, 프로그램이 실행되는 도중에, 프로그램의 정상적인 작동 흐름을 방해하는 특정한 이벤트가 발생하면, 그 이벤트를 Exception이라고 한다.
개발을 하면서 우리는 Exception이 발생했을 때 에러가 발생했다고 말한다. 에러의 통상적인 정의가 '오류'이기 때문인데, 그러나 자바에는 Error 클래스도 있고 Exception 클래스도 있다. 자바에서 에러와 예외는 개념적으로 다른 표현이다.
2. Error vs Exception
Exception hierarchy >
위 사진은 Exception에 대한 클래스 구조도다. Error와 Exception 둘 다 Throwable의 하위 클래스다.
- Error
애플리케이션이 실행되는 환경에서 주로 발생하는 오류를 의미한다. Error 클래스 하위에 ThreadDeath, IOError, OutOfMemoryError, StackOverflowError 가 있는 걸 보면 Error가 대체로 어떤 상황에서 발생하는지 짐작이 갈 것이다. 프로그램이 실행되는 도중에 메모리가 없어서 강제종료되는 상황은 환경에 대한 문제다.
Error는 catch로 잡아도 애플리케이션 로직으로 복구할 수 없다.
따라서 Error를 일부러라도 catch로 잡아서는 안 된다. 스택트레이스가 안 남기라도 하면 에러가 왜 발생했는지 알 수 없기 때문이다.
또한 런타임 중에만 발생하므로, 컴파일 단계에서는 감지할 수 없다.
- Exception
예외는 애플리케이션 내부에서 발생한다. 예를 들면, NullPointException처럼 개발자 실수로 자주 발생하는 예외가 그렇다.
애플리케이션이 기동되는 환경에 문제가 생긴 건 아니므로 catch로 잡으면 복구가 가능하다.
Exception은 또 검사예외(Checked Exception)와 비검사예외(Unchecked Exception)으로 나뉜다.
- 검사 예외(Checked Exception)
검사 예외는 컴파일 에러와 관련이 있다. 사용하려는 메서드가 검사 예외를 던진다고 정의되어있다면, 메서드를 사용할 때 무조건 catch로 예외를 잡아주거나, 상위 메서드로 예외를 던져야 한다. 아니면 컴파일 에러가 난다.
예를 들면, InputStream, OutputStream을 쓸 때 try-catch가 없어서 컴파일에러가 발생한 일이 한 번쯤은 있을 것이다.
InputStream의 read 메서드를 보면 IOException이 발생했을 때 상위 메서드에서 예외를 처리하도록 정의되어있다.
IOException은 Exception을 상속한다.
검사예외는 예외가 발생한 뒤에도 프로그램을 복구할 수 있음직한 상황일 때 발생한다. 발생한 예외를 try-catch나 throw로 처리할 것을 강제함으로서, 사용자에게 프로그램 흐름을 회복할 것을 요구하는 것이다.
그러므로 검사예외는 API설계자가 보내는 일종의 메시지이기도 하다.
- 비검사 예외(Unchecked Exception)
비검사 예외는 런타임 에러와 관련이 있다. 위에서 첨부한 Throwable 구조도를 다시 보면 Exception은 RuntimeException과 기타 다른 Exception들로 분류되는데, RuntimeException을 상속하는 클래스는 전부 비검사 예외다.
비검사 예외는 try-catch나 throw같은 예외처리를 강제하지 않는다. 비검사 예외가 발생하는 상황이 예외가 발생했을 때 의미있는 조치를 취하기가 어렵거나 불명확한 상황이기 때문이다.
예를 들어 ArrayIndexOutOfBoundsException가 발생한다면, catch로 예외를 잡는다고 해도 의미있는 조치를 취하기가 힘들다.
또한 만약 NullPointException이 검사예외였다면 NullPointException이 발생할만한 모든 메서드에 예외처리를 해야 했을 거고, 그러면 코드의 가독성도 굉장히 안 좋아졌을 것이다. 이런 예외에 대해서는 예외처리를 강제하지 않는 게 좋으므로, 대부분의 예외는 예외처리를 강제했을 때 효과가 있을 경우에만 검사예외로 설계된다.
비검사 예외는 컴파일 단계에서 잡을 수 없고, 런타임 중에 발생한다.
3. 내용 정리
- Exception이란?: 프로그램이 실행되는 도중에 발생하는 프로그램의 정상 동작을 방해하는 이벤트
- Error: 프로그램 실행 환경에 문제가 생겼을 때 발생. 발생하면 프로그램 복구가 불가능하므로 catch로 잡아도 소용없음.
- 검사 예외(Checked Exception): 컴파일 타임에 발생하며 사용자가 예외처리를 무조건 해줘야 한다. 예외처리를 하는 게 분명하게 의미가 있을 때만 예외를 검사예외로 선언한다.
- 비검사 예외(Unchecked Exception): 런타임 중에 발생한다. 예외처리의 필요가 강제되지 않는다.
4. 참고자료
이펙티브 자바 서적
https://docs.oracle.com/javase/tutorial/essential/exceptions/definition.html
https://www.javamadesoeasy.com/2015/05/exception-handling-exception-hierarchy.html
https://javaconceptoftheday.com/difference-between-error-vs-exception-in-java/
'java' 카테고리의 다른 글
[230827] Exception에 관해서 (2) - StackTrace (0) | 2023.08.27 |
---|---|
[230813] java TreeMap (0) | 2023.08.13 |
[230805] [google drive api] java api 사용하기 (3) - 파일 검색 코드 작성 (0) | 2023.08.05 |
[211005] JNI(Java Native Interface)로 C++ dll 사용하기 - cmd 사용 (0) | 2021.10.05 |
[210623] spring boot - error page 만들기 (0) | 2021.06.23 |