본문 바로가기
Effective Java

[Effective Java] 아이템69 예외는 진짜 예외 상황에만 사용하라

by byeongoo 2021. 8. 22.

■ 예외는 예외 진짜 예외 상황에서만 사용하라

아래 코드는 예외를 잘못 사용한 코드이다. 무한 루프를 돌다가 배열의 끝에 도달해 예외가 발생하면 끝을 내는 코드이다.

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

 

반복문에서 배열의 크기보다 커졌는지 검사를 하는 부분을 줄이려고 의도한 코드 였을 텐데, 이는 잘못된 추론이다.

 

  • 예외는 예외 상황에 쓸 용도로 설계되었으므로 JVM 구현자 입장에서는 명확한 검사만큼 빠르게 만들어야 할 만큼 최적화에 신경쓰지 않았을 확률이 높다.
  • 코드를 try-catch 블록 안에 넣으면 JVM이 적용할 수 있는 최적화가 제한된다.
  • 배열을 순회하는 표준 관용구는 앞서 걱정한 중복 검사를 수행하지 않는다. JVM이 알아서 최적화해서 없애준다.

즉, 코드를 헷갈리게 할 뿐만 아니라 성능을 떨어뜨리고 심지어 제대로 동작하지 않을 수도 있다.

 

● 예외는 오직 예외 사오ㅘㅇ에서만 사용하라. 절대로 흐름 제어용으로 사용하면 안된다.

● 잘 설계된 API라면 클라이언트가 정상적인 제어 흐름에서 예외를 사용할 일이 없게 해야 한다.

 

 

■ 상태 검사 메서드

상태 의존적 메서드는 반드시 상태 검사 메서드도 함께 제공해야 한다.(Iterator의 next, hasNext)

 for (Iterator<Foo> i = collections.iterator(); i.hasNext();) {
    Foo foo = i.next();
    // ...
}

아래 코드는 상태 검사 메서드가 없을 때 예외 처리로 처리하고 있는 코드 이다.

try {
    Iterator<Foo> i = collection.iterator();
    while (true) {
        Foo foo = i.next();
        // ...
    }
} catch (NoSuchElementException e) {

}

 

■ 참고사항

  • 외부 동기화 없이 여러 스레드가 동시 접근 가능하거나 상태가 변할 수 있다면 옵셔널을 사용한다.
  • 성능이 중요한 상황에서 상태 검사 메서드가 상태 의존적 메서드의 작업 일부를 중복 수행한다면 옵셔널 반환을 선택한다.
  • 그 외의 경우에는 상태 검사 메서드 방식이 더 낫다.