본문 바로가기
Language/Effective java

예외

by y.j 2022. 8. 17.
728x90

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

아래 코드는 끔찍하다. 가독성도 떨어질 뿐 아니라 예외를 쓸 필요가 없다.

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

수정 후

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

 

왜 배열의 접근을 try-catch문으로 작성한 것일까? JVM은 배열을 접근할 때마다 경계를 넘지 않는지 검사하는데 일반적인 반복문도 배열 경계에 도달하면 종료한다. 위 코드는 하지 않아도 될 예외처리를 했기 때문에 오해의 가능성이 있고 디버깅을 어렵게 한다.

 

잘못된 3가지 이유

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

 

예외는 오직 예외 상황에서만 써야 한다. 절대로 일상적인 제어흐름용으로 쓰여선 안된다. 

 성능 개선 목적으로 과하게 머리를 쓴 기법을 자제하라. 실제로 성능이 좋아지더라도 자바 플랫폼이 꾸준히 개선되고 있으니 최적화로 얻은 상대적인 성능 우위가 오래가지 않을 수 있으며 성능 향상이 있더라도 JVM이 개선되고 있으니 오래가지 않을 수 있다.

 

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

특정 상태에서만 호출 할 수 있는 '상태 의존적' 메서드를 제공하는 클래스는 '상태 검사'메서드도 함께 제공해야 한다. 하나의 예제로 Iterator를 예제로 들 수 있는데 상태검사도 할 수 있기 때문에 아래와 같이 for문으로 사용 할 수 있다.

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

 

상태 검사 메서드, 옵셔널, 특정 값 중 하나를 선택하는 지침

  • 외부 동기화 없이 여러 스레드가 동시에 접근할 수 있거나 외부요인으로 상태가 변할 수 있다면 옵셔널이나 특정 값을 사용한다. 상태 검사 메서드와 상태 의존적 메서드 호출 사이에 객체의 상태가 변할 수 있기 때문이다.
  • 성능이 중요한 상황에서 상태 검사 메서드가 상태 의존적 메서드의 작업 일부를 수행한다면 옵셔널이나 특정 값을 선택한다.
  • 다른 모든 경우엔 상태 검사 메서드 방식이 조금 더 낫다고 할 수 있다. 가독성이 살짝 더 좋고, 잘못 사용했을 때 발견하기가 쉽다. 상태 검사 메서드 호출을 잊었다면 의존적 메서드가 예외를 던져 버그를 확실히 드러낼 것이다. 반면 특정 값은 검사하지 않고 지나쳐도 발견하기가 어렵다.

 

복구할 수 있는 상황에는 검사 예외를 프로그래밍 오류에는 런타임 예외를 사용하라

자바의 문제 상황을 알리는 타입으로 검사 예외, 런타임 예외, 에러 이렇게 세 가지를 제공하는데 언제 무엇을 사용해야 할까?

 

호출쪽에서 복구하리라 여겨지는 상황이라면 검사 예외를 사용하라. 

검사예외를 던지면 API사용자에게 알려줄 수 있다. 사용자는 예외를 잡기만 하고 별다른 조치를 취하지 않을 수 있기 때문에 좋은 방법은 아니다.

 

프로그래밍 오류를 나타낼 때는 런타임 예외를 사용하자.

런타임 예외의 대부분은 전제조건을 만족하지 못했을 때 발생한다. 전제조건 위배란 단순히 클라이언트가 해당 API명세에 기록된 제약을 지키지 못했다는 뜻이다. 예를 들어 Array의 인덱스 0 ~ 배열크기 -1까지여야 한다. 이것을 지키지 못하면 ArrayIndexOutOfBoundsException이 발생했다는 것이다.

 

Error 클래스를 상속해 하위 클래스를 만드는 일은 자제하자.

구현하는 비검사 throwable은 모두 RuntimeException의 하위 클래스여야 한다. Error는 상속하지 말아야 할 뿐 아니라 throw문으로 직접 던지는 일도 없어야 한다.

 

 

 

 

728x90

'Language > Effective java' 카테고리의 다른 글

예외  (0) 2022.08.19
예외  (0) 2022.08.18
일반적인 프로그래밍 원칙  (0) 2022.08.12
일반적인 프로그래밍 원칙  (0) 2022.08.11
일반적인 프로그래밍 원칙  (0) 2022.08.10

댓글