DEV ℧ Developer Diary

[EffectiveJava] item72 - 표준 예외를 사용하라

예외도 일반 코드와 마찬가지로 재사용하는 것이 좋으며, 자바 라이브러리는 대부분 API에서 쓰기에 충분한 수의 예외를 제공한다.

표준 예외의 재사용

표준 예외를 재사용 하면 아래와 같은 이점이 있다.

  1. 규약을 그대로 따르기 때문에 API가 다른사람이 익히고 사용하기가 쉬워진다.
  2. 개발한 API를 사용한 프로그램도 낯선 예외를 사용하지 않게 되어 읽기 쉽게 된다.
  3. 예외 클래스 수가 적을수록 메모리 사용량도 줄고 클래스를 적재하는 시간도 적게 걸린다.

IllegalArgumentException

가장 많이 재사용 되는 예외는 IllegalArgumentException 이다. 호출자가 인수로 부적절한 값을 넘길 때 던지는 예외이다.

예를 들어 반복 횟수를 지정하는 매개변수에 음수를 건넬 때 쓸 수 있다.

IllegalStateException

IllegalStateException 예외도 자주 재사용 된다. 이 예외는 대상 객체의 상태가 호출된 메서드를 수행하기에 적합하지 않을 때 주로 던진다.

예를 들어 제대로 초기화되지 않은 객체를 사용하려 할 때 던질 수 있다.

NullPointerException, IndexOutOfBoundsException

메서드가 던지는 모든 예외를 잘못된 인수나 상태라고 뭉뚱그릴 수도 있겠지만, 그중 트구한 일부는 따로 구분해 쓰는 게 보통이다.

null 값을 허용하지 않는 메서드에 null 값을 던지면 NullPointerException을 던진다.

어떤 시퀀스의 허용 범위를 넘는 값을 건넬 때도 IndexOutOfBoundsException를 던진다.

ConcurrentModificationException

단일 스레드에서 사용하려고 설계한 객체를 여러 스레드가 동시에 수정하려 할때 던진다.
(외부 동기화 방식으로 사용하려고 설계한 객체도 마찬가지다).

사실 동시 수정을 확실히 검출할 수 있는 안정된 방법은 없으니, 이 예외는 문제가 생길 가능성을 알려주는 정도의 역할로 쓰인다.

UnsupportedOperationException

클라이언트가 요청한 동작을 대상 객체가 지원하지 않을 때 던진다.

대부분 객체는 자신이 정의한 메서드를 모두 지우너하니 흔히 쓰이는 예외는 아니다. 보통은 구현하려는 인터페이스의 메서드 일부를 구현할 수 없을 때 쓰인다.

예를 들어 원소를 넣을 수만 있는 List 구현체에 누군가 remove 메서드를 호출하면 이 예외를 던질 것이다.

표준 예외의 선택

표준 예외를 선택할 때 헷갈릴 수 있다. 예시를 들어 어떤 표준예외를 선택할지 참고하도록 하자.

예시

인수로 건넨 수만큼의 카드를 뽑아 나눠주는 메서드

  • 인수의 값이 카드의 수보다 너무 클경우 : IllegalArgumentException
  • 덱에 남은 카드 수가 인수보다 너무 적을 경우 : IllegalStateException

간단하게 정리하자면 다음과 같다. 인수 값이 무엇이었든 실패했을 경우는 IllegalStateException, 그렇지 않으면 IllegalArgumentException을 던지자

재사용 금지 예외

Exception, RuntimeException, Throwable, Error는 직접 재사용하지 말자. 이 클래스들은 추상 클래스라고 생각해야 한다.

이 예외들은 다른 예외들의 상위 클래스이므로, 즉 여러 성격의 예외들을 포괄하는 클래스이므로 안정적으로 테스트 할 수 없다.

재사용 예외 정리

예외 주요 쓰임
IllegalArgumentException 허용하지 않는 값이 인수로 건네졌을 때
(null은 따로 NullPointerException으로 처리)
IllegalStateException 객체가 메서드를 수행하기에 적절하지 않은 상태일 때
NullPointerException null을 허용하지 않는 메서드에 null을 건넸을 때
IndexOutOfBoundsException 인덱스가 범위를 넘어섰을 때
ConcurrentModificationException 허용하지 않는 동시 수정이 발견됐을 때
UnsupportedOperationException 호출한 메서드를 지원하지 않을 때
ArithmeticException 예외 적인 산술 조건이 발생 할 때 (0으로 나누기)
NumberFormatException 숫자가 아닌 형식을 숫자로 변환하려 할 때

주로 쓰이는 예외 외에 다른 예외도 재사용 할 수 있다.

복소수나 유리수를 다루는 객체를 작성한다면 ArithmeticExceptionNumberFormatException같은 예외도 재사용 할 수 있을 것이다.

상황에 부합한다면 항상 표준 예외를 재사용 하자.

더 많은 정보를 가진 예외

더 많은 정보를 제공하길 원한다면 표준 예외를 확장해도 좋다.

단, 예외는 직렬화할 수 있다. 직렬화에는 많은 부담이 따르니, 나만의 예외를 새로 만드는것은 자제하도록 하자.