try {
int i = 0;
while(true) {
range[i++].climb();
}
} catch (ArrayIndexOutOfBoundsException e) {
}
이 코드는 배열의 원소를 순회하다가 배열의 끝에 도달하면 ArrayIndexOutOfBoundsException을 발생시켜 끝을 내고 있음
잘못된 추론을 근거로 성능을 높여보려 했음 (JVM은 배열에 접근할 때마다 경계를 넘지 않는지 검사하는데, 일반적인 반복문도 배열 경계에 도달하면 종료함 : 중복되는 일 하나를 생략)
예외를 사용한 것이 표준 관용구보다 느림
//표준 관용구
for (Mountain m : range)
m.climb();
반복문 안에 버그가 있다면 흐름 제어에 쓰인 예외가 버그를 숨겨 디버깅을 어렵게 함
ex) 반복문 내부에서 관련 없는 배열을 사용하다가 ArrayIndexOutOfBoundsException을 일으킨 경우 버그 때문에 발생한 예외를 정상적인 반복문 종료 상황으로 오해하게 됨
⇒ 예외는 오직 예외 상황에서만 써야 하며, 절대 일상적인 제어 흐름용으로 사용하지 말자
잘 설계된 API라면 클라이언트가 정상적인 흐름에서 예외를 사용할 일이 없게 해야 함
→ 특정 상태에서만 호출할 수 있는 상태 의존적인 메서드를 제공하는 클래스는 상태 검사 메서드도 함께 제공해야 함 ex) Iterator 인터페이스의 next, hasNext
// 상태검사 메서드 덕분에 표준 for 관용구를 사용할 수 있음
for (Iterator<Foo> i = collection.iterator(); i.hasNext(); ) {
Foo foo = i.next();
// Some tasks...
}
// hasNext를 제공하지 않았다면 클라이언트에서 예외 처리를 해야 함
try {
Iterator<Foo> i = collection.iterator();
while (true) {
Foo foo = i.next();
// Some tasks ...
}
} catch (NoSuchElementException e) {
}
외부 동기화 없이 여러 스레드가 동시에 접근할 수 있거나 외부 요인으로 상태가 변할 수 있다면 옵셔널이나 특정 값을 사용
→ 상태 검사 메서드와 상태 의존적 메서드 호출 사이에 객체의 상태가 변할 수 있기 때문
성능이 중요한 상황에서 상태 검사 메서드가 상태 의존적 메서드의 작업 일부를 중복 수행한다면 옵셔널이나 특정 값을 선택
위의 경우를 제외하면 상태 검사 메서드 방식이 조금 더 나음
→ 가독성이 더 좋고, 잘못 사용했을 때 발견하기 쉬움
→ 상태 검사 메서드 호출을 잊었다면 상태 의존적 메서드가 예외를 던져 버그를 확실히 드러냄
→ 반면에 특정 값을 사용하는 방식은 검사하지 않고 지나쳐도 발견하기가 어려움