69. 예외는 진짜 예외 상황에만 사용하라.


반례

예외를 진짜 예외상황이 아닌 상황에 사용한다는게 무엇일까? 다음 코드를 보자.

try {
	int i = 0;
	while(true) {
		range[i++].climb();
	}
} catch(ArrayIndexOutOfBoundsException e) { }

이 코드는 무한 루프를 돌다가 배열의 끝에 도달해 ArrayIndexOutOfBoundsException 예외가 발생하면 catch문에서 아무 동작도 하지 않고 끝내는 로직으로, 예외를 일종의 제어 흐름용으로 사용한 것이다. 그냥 for-each문을 사용하면 되는데, 어째서 위와 같이 작성한 것일까?

for (Mountain m : range){
	m.climb();
}

그 이유는 잘못된 추론에 연원한 최적화시도이다.

JVM은 배열에 접근할 때마다 경계를 넘지 않는지 검사하는데, 일반적인 반복문도 배열 경계에 도달하면 종료한다. 그래서 위와 같은 코드로 배열 경계에서 검사되는 로직을 하나 제거한 것이다.

하지만, 이런 최적화는 세 가지 부분에서 잘못된 추론이다.

  1. 예외의 용도 자체가 예외 상황을 고려해서 만든 것이기에 JVM 구현자는 명확한 검사만큼 빠르게 만들 이유가 별로 없기에 최적화가 안되있을 확률이 높다.
  2. 코드를 try-catch 블럭에 넣으면 JVM이 적용할 수 있는 최적화가 제한된다.
  3. 배열을 순회하는 표준 관용구는 앞서 고민했던 중복 검사를 수행하지 않고 JVM이 알아서 최적화 해준다.

즉, 위와 같이 예외를 사용한 최적화를 할 필요가 없으며 오히려 더 느리게 동작한다.