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

다음과 같이 예외를 예외 상황이 아닌 경우에 사용하는 것을 지양하라고 언급하고 있다.

1
2
3
4
5
6
7
8
9
10
// 굳이 예외를 써서 루프를 종료 
try{
int i = 0;
while(true){
range[i++].climb();
}
}
catch(ArrayIndexOutOfBoundException e){
//
}

위와 같이 예외가 아닌 상황에 사용하게 되면 가독성이 떨어지는 것은 물론 다음과 같은 단점들도 있다고 한다.

  1. 예외는 예외 상황에 쓰도록 설계되었으므로, JVM 구현체에서 명확한 검사만큼 최적화되지 않았을 가능성이 크다.
  2. 코드를 try-catch 블록 안에 넣으면 JVM이 적용할 수 있는 최적화가 제한된다.
  3. 향상된 for문으로 사용하면 중복검사를 알아서 JVM이 최적화함으로 굳이 위처럼 예외처리 할필요가 없다.
1
2
3
4
// 표준 배열 순회 관용구 
for(Mountain m : range ){
m.climb();
}
  1. 디버깅을 어렵게 만든다. 다른 반복문이 ArrayIndexOutOfBoundException 을 터트린다고 가정하였을때, 첫번쨰 잘못된 예시는 이를 반복문 종료 상황으로 판단한다.

상태 검사 method

  • 잘 설계된 API는 client가 정상적인 제어 흐름에서 예외 처리를 할일이 없게 해야 한다. 예를 들면 특정 상태에서만 호출할 수 있는 상태 의존적 method를 제공하는 class는 상태 검사 method도 함께 제공하여서 별도로 예외 처리를 하지 않도록 만들어주어야 한다.

ex) Iterator interface의 next, hasNext가 각각 상태 의존, 상태 검사 method에 해당된다.

1
2
3
4
// 올바른 예시
for(Iterator<Foo> i = collection.iterator(); i.hasNext(); ){
Foo foo = i.next();
}
  • 상태 검사 method를 제공하지 않는다면 예외 상황이 아닌데도 불구하고 예외 처리 로직이 들어간다.
1
2
3
4
5
6
7
8
try{
Iterator<Foo> i =collection.iterator();
while(true){
Foo foo = i.next();
}
}catch(NoSuchElementException e){
//
}
  • 상태 검사 method를 대신해 빈 Optional , null값을 반환하는 방법도 있다. 이를 선택하는 기준을 책에서는 다음과 같이 제시하고 있다.
  1. 멀티 쓰레드 상황에서는 상태 검사하는 method 호출하는 직전에 객체의 상태가 변할수 있다. –> null / optional 사용
  2. method 호출 하나도 성능 최적화를 위해서 제거해야하는 경우 –> null / optional 사용
  3. 그 외에는 가독성이 좋은 상태 검사 method를 호출하는 것을 권고

Comments