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

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

    • 예외는 진짜 예외 상황에서만 사용해야함.
    • 예외를 잘못 사용한 예시
      • 흐름제어에 예외를 사용함 → 흐름제어에 사용된 예외 때문에 진짜 예외가 무시되어 디버깅이 어려워 질 수 있음.
    • 예외 대신 흐름제어에 사용할만한 것
      • Optional
      • 상태 검사 메서드
      • 특정 값 중 하나 선택 
    • 선택 기준
      • Optional이나 특정값 사용
        • 상태 검사 메서드 - 상태 메서드 사이에 동시성 문제가 있을 수 있는 경우
        • 성능이 중요한데, 상태 검사 메서드 / 상태 메서드가 중복된 작업이 일부 있는 경우
      • 나머지 경우
        • 상태 검사 메서드 사용하는 것이 유리.

     


    예외를 잘못 사용한 경우. 

    아래 코드는 무엇을 의미하는 것일까? 단순히 코드만 봤을 때는 무엇을 하는지 전혀 알 수 없다. 

    // 아래 코드는 무엇을 의미할까? 
    public static void main(String[] args) {
        Climber[] range = new Climber[0];
        try {
            int i = 0;
            while (true) {
                range[i++].climb();
            }
        } catch (ArrayIndexOutOfBoundsException e) {
        }
    }

    작성자가 이 코드를 만든 이유는 For문 - 배열 사이의 최적화를 하기 위함이다. For문도, 배열도 한번씩 '끝'인지를 체크하는데 그 과정이 두 번 반복되어 최적화 하기 위해서 위의 코드가 만들어졌다. 그렇지만 위의 코드는 몇가지 문제점이 있다.

    • 실제로 성능 개선에 영향이 없을 수 있음. 
    • 이해하기 어려움.
    • 반복문 안에서 버그가 발생한다면, 흐름제어에 쓰인 예외가 버그를 숨기는 역할을 할것임.

    이런 문제점은 예외를 '예외 상황이 아닐 때' 사용했기 때문에 발생한다. 만약 위의 코드를 아래처럼 작성했다면 읽기 편하고, 예외 상황에서도 문제를 디버깅할 때 편리할 것이다.

    for (Climber climber : range) {
        climber.climb();
    }

     


    흐름제어에 예외를 사용하는 대신 다른 것을 쓰자.

    흐름제어를 하기 위해 예외를 사용하는 것은 가독성은 물론이고 프로그램 자체의 견고함에도 문제를 발생시킨다. 따라서 이런 것들을 지양해야한다. 흐름제어에 예외 대신 사용할 수 있는 것은 세 가지 정도가 있다.

    • 특정한 값을 사용. 
    • 상태 검사 메서드 - 상태 메서드 제공
    • Optional 제공

    상태 검사 메서드 - 상태 메서드 제공은 이를테면 Iterator 인스턴스가 가지고 있는 next(), hasNext() 메서드다. 흐름 제어에 예외를 사용하는 대신에 상태 검사 메서드를 통과하면 상태 메서드를 호출할 수 있는 식으로 짝을 맞춰주면 된다. 

    for (Iterator<Climber> iterator = climbers.iterator(); iterator.hasNext();) {
        Climber climber = iterator.next();
        climber.climb();
    }

    위에서는 상태 검사 메서드 hasNext()로 검사를 한 후에, 상태 메서드인 next()를 호출해서 필요한 작업을 처리하도록 했다. 

     


    각각 언제 쓰면 좋을까?

    위에서 이야기 한 것처럼 흐름 제어로 예외를 사용하는 대신에 사용할 수 있는 것은 세 가지가 있다고 했다. 그러면 각각은 언제 사용하는 것이 적절할까? 

     

    동시성 문제가 있는 경우 → Optional, 특정값을 사용

    만약에 동시성 문제가 있을 것으로 예상된다면 Optional이나 특정값을 사용하도록 해야한다. 왜냐하면 상태 검사 메서드 - 상태 메서드 사이에는 다른 쓰레드가 들어와서 작업할 수 있는 여지가 존재하기 때문이다. 

    아래 코드에서는 그럴 일이 없겠지만, 억지로 예를 들어보면 hasNext()를 호출한 결과를 받고 next()를 실행하려고 하는 사이에 다른 쓰레드에 의해서 상태 검사 메서드의 값이 바뀔 수도 있다. 이런 경우가 예상된다면 Optional이나 특정값을 반환하도록 사용해야 한다. 

    for (Iterator<Climber> iterator = climbers.iterator(); iterator.hasNext();) {
        Climber climber = iterator.next();
        climber.climb();
    }

     

    성능 문제가 있는데, 상태 검사 - 상태 메서드가 중복된 일을 하는 경우

    예를 들어 상태 검사 - 상태 메서드와 관련된 블록쪽에 성능 문제가 발생하고 있다. 그런데 이 때 상태 검사 - 상태 메서드가 중복된 일을 하는 경우에는 성능에 영향을 주고 있는 상황이 있을 수도 있다. 

    이 때 성능 테스트를 해서 병목 구간이 상태 검사 - 상태 메서드의 중복 작업때문이라고 한다면, 특정값 - Optional을 반환하도록 한다.

     

    나머지 → 상태 검사 - 상태 메서드 사용

    위의 두 가지를 제외한 나머지 상태 검사 - 상태 메서드를 사용하는 것이 가장 좋다. 

    댓글

    Designed by JB FACTORY