예외는 오직 예외 상황에서만 써야 한다. 절대로 일상적인 제어 호름용으로 쓰여선 안 된다. 더 일반화해 이야기하면 표준적이고 쉽게 이해되는 관용구를 사용하고, 성능 개선을 목적으로 과하게 머리를 쓴 기법은 자제하라. 실제로 성능이 좋아지더라도 자바 플랫폼이 꾸준히 개선되고 있으니 최적화로 얻은 상대적인 성능 우위가 오래가지 않을 수 있다. 반면 과하게 영리한 기법에 숨겨진 미묘한 버그의 폐해와 어려워진 유지보수 문제는 계속 이어질 것이다.
이 원칙은 API 설계에도 적용된다. 잘 설계된 API라면 클라이언트가 정상적인 제어 흐름에서 예외를 사용할 일이 없게 해야 한다. 특정 상태에서만 호출할 수 있는 '상태 의존적' 메소드를 제공하는 클래스는 '상태 검사' 메소드도 함께 제공해야 한다. 예를 들어 Iterator 인터페이스의 next와 hasNext가 각각 상태 의존적 메소드와 상태 검사 메소드에 해당한다. 그리고 별도의 상태 검사 메소드 덕분에 표준 for 관용구를 사용할 수 있다(for-each도 내부적으로 hasNext를 사용한다).
상태 검사 메소드 대신 사용할 수 있는 선택지도 있다. 올바르지 않은 상태일 때 빈 옵셔널 혹은 null 같은 특수한 값을 반환하는 방법이다. 상태 검사 메소드, 옵셔널, 특정 값 중 하나를 선택하는 지침을 몇 개 소개하겠다.
1. 외부 동기화 없이 여러 스레드가 동시에 접근할 수 있거나 외부 요인으로 상태가 변할 수 있다면 옵셔널이나 특정 값을 사용한다.
상태 검사 메소드와 상태 의존적 메소드 호출 사이에 객체의 상태가 변할 수 있기 때문이다.
2. 성능이 중요한 상황에서 상태 검사 메소드가 상태 의존적 메소드의 작업 일부를 중복 수행한다면 옵셔널이나 특정 값을 선택한다.
3. 다른 모든 경우엔 상태 검사 메소드 방식이 조금 더 낫다고 할 수 있다.
가독성이 살짝 더 좋고, 잘못 사용했을 때 발견하기가 쉽다.
상태 검사 메소드 호출을 깜빡 잊었다면 상태 의존적 메소드가 예외를 던져 버그를 확실히 드러낼 것이다.
반면 특정 값은 검사하지 않고 지나쳐도 발견하기가 어렵다(옵셔널에는 해당하지 않는 문제다).
예외는 예외 상황에서 쓸 의도로 설계되었다. 정상적인 제어 흐름에서 사용해서는 안 되며, 이를 프로그래머에게 강요하는 API를 만들어서도 안 된다.