📌 예외를 잘못 사용한 경우
try {
int i = 0;
while(true)
[rangepi++].climb();
} catch (ArrayIndexOutOfBoundsException e) {
...
}
- 직관적이지 않다는 사실만으로도 이렇게 작성해선 안 된다.
- 잘못된 추론을 근거로 성능을 높이려 했다. (JVM에서 경계를 넘는지 확인하므로 반복문에서도 검사하면 중복일 것이라는 가정)
- 예외는 예외 상황에만 쓸 용도로 설계되어 JVM 구현자 입장에서 최적화에 별로 신경 쓰지 않았을 가능성이 크다.
- try-block을 사용하면 JVM이 적용할 수 있는 최적화가 제한된다.
- 배열을 순회하는 표준 관용구는 중복 검사를 수행하지 않는다. JVM이 알아서 최적화해 없애준다.
- 예외를 사용한 쪽이 표준 관용구보다 훨씬 느리다.
- 제대로 동작하지 않을 수 있다.
- 흐름 제어에 쓰인 예외가 버그를 숨겨 디버깅을 훨씬 어렵게 한다.
- 표준 관용구였다면 버그는 예외를 잡지 않고 스택 추적 정보를 남긴 채 스레드를 즉각 종료시켰을 것이다.
- 예외를 사용한 반복문은 버그로 발생한 엉뚱한 예외를 정상적인 반복문 종료 상황으로 오해하고 넘긴다.
📌 예외는 오직 예외 상황에서만 사용하라
- 예외를 절대 일상적인 제어 흐름용으로 사용하지 마라
- 표준적이고 쉽게 이해되는 관용구를 사용하라.
- 성능 개선을 목적으로 과하게 머리를 쓴 기법은 자제하라.
- 실제로 성능이 개선되더라도 자바 플랫폼이 꾸준히 개선되므로 상대적 성능 우위가 오래 가지 않을 수 있다.
- 과하게 영리한 기법에 숨겨진 미묘한 버그와 유지보수의 어려움으로 인한 피해가 커질 것이다.
for (Iterator<Foo> i = collection.iterator(); i.hasNext(); ) {
Foo foo = i.next();
..
}
// Iterator가 hasNext를 제공하지 않았을 경우 (이렇게 쓰지 말 것!)
try {
Iterator<Foo> i = collection.iterator();
while(true) {
Foo foo = i.next();
...
}
} catch (NoSuchElementException e) { ... }
- 잘 설계된 API라면 Client가 정상적인 제어 흐름에서 예외를 사용할 일이 없게 해야 한다.
- 특정 상태에서만 호출 가능한 상태 의존적 메서드(next)를 제공하는 클래스(Iterator)는 상태 검사 메서드(hasnext)도 함께 제공해야 한다.
📌 상태 검사 메서드, 옵셔널, 특정 값 중 선택 사항
- 외부 동기화 없이 여러 thread가 동시 접근 가능하거나 외부 요인으로 상태가 변경 가능한 경우
- Optional이나 특정 값을 사용하라.
- 상태 검사 메서드와 상태 의존적 메서드 호출 사이에 객체의 상태가 변할 수 있다.
- 성능이 중요한 상황에서 상태 검사 메서드가 상태 의존적 메서드의 작업을 일부 중복 수행하는 경우
- Optional이나 특정 값을 사용하라
- 다른 모든 경우
- 대부분 상태 검사 메서드 방식이 조금 더 낫다.
- 가독성, 오류 검출 측면에서 좋다.
- 예외가 발생해도 상태 의존적 메서드가 예외를 던져 버그를 확실히 잡아낼 것이다.