예외를 사용할때는, 이미 자바 라이브러리에서 제공하고 있는 예외들, 즉 표준 예외를 사용하는 것이 좋다. 또한, 이름뿐 아니라 예외가 던져지는 맥락도 부합할 때만 재사용해야 한다.
표준 예외를 재사용한다면 아래와 같은 장점이 존재한다.
호출자가 인수로 부적절한 값을 넘길 때 던지는 예외로, 예를 들어 반복 횟수를 지정하는 매개변수에 음수를 건넬 때 사용할 수 있다.
🔖 특수한 경우
NullPointerException
:null
값을 허용하지 않는 메서드에null
을 건네는 경우 던진다.
IndexOutOfBoundsException
: 시퀀스의 허용 범위를 넘는 값을 건네는 경우 던진다.
대상 객체의 상태가 호출된 메서드를 수행하기에 적합하지 않을 때 주로 던지는 예외이다. 예를 들어, 제대로 초기화되지 않은 객체를 사용하려 할 때 던질 수 있다.
단일 스레드에서 사용하려고 설계한 객체를, 여러 스레드가 동시에 수정하려 할 때 던지는 예외이다. (외부 동기화 방식으로 사용하려고 설계한 객체도 마찬가지) 동시 수정을 확실히 검출할 수 있는 안정된 방법은 없으니, 이 예외는 문제가 생길 가능성을 알려주는 정도의 역할로 쓰인다.
클라이언트가 요청한 동작을 대상 객체가 지원하지 않을 때 던진다. 대부분 객체는 자신이 정의한 메서드를 모두 지원하니 흔히 쓰이는 예외는 아니지만, 보통 구현하려는 인터페이스의 메서드 일부를 구현할 수 없을 때 쓴다.
예를 들어 원소를 넣을 수만 있는 List
구현체에 대고 누군가 remove
를 호출하면 이 예외를 던질 것이다.
Exception, RuntimeException, Throwable, Error 는 직접 재사용하지 말자.
다른 예외들의 상위 클래스이므로, 여러 성격의 예외들을 포괄하는 클래스이므로 안정적으로 테스트할 수 없기 때문이다.
🔖 주의 사항
더 많은 정보를 제공하기 원한다면, 표준 예외를 확장해도 좋지만 예외는 직렬화할 수 있다는 사실을 기억해야 한다(아이템 12). 직렬화에는 많은 부담이 따르니, 나만의 예외를 새로 만들지 않는 것이 좋다.
카드 덱을 표현하는 객체가 있고, 인수로 건넨 수만큼의 카드를 뽑아 나눠주는 메서드에서 덱에 남아 있는 카드 수보다 큰 값을 건네는 경우 어떤 예외를 던져야 할까?
IllegalArgumentException
IllegalStateException
대개는 위와 같이 선택할 것이지만, 이런 상황에서의 일반적인 규칙은 다음과 같다.
🔖 일반적인 규칙
IllegalStateExceptpion
: 인수 값이 잘못 들어왔는데, 무엇이었든 어차피 실패했을 경우
IllegalArguementException
: 인수 값이 정상으로 들어왔을때 성공했을 경우