-
item 69 예외는 진짜 예외 상황에만 사용하라책/이펙티브 자바 2022. 4. 22. 15:09
ITEM 69 예외는 진짜 예외 상황에만 사용하라
운이 없다면 아래와 같은 코드를 마주칠 수도 있다
예외를 완전히 잘못 사용한 예 try { int i=0; while(true) range[i++].climb(); } catch (ArrayIndexOutOfBoundsException e) { } 무슨 일을 하는지 알 수 없는 직관적이지 않은 코드이며 배열의 원소를 아주 끔직한 방법으로 순회하고 있다 무한루프를 돌다가 배열의 끝에 도달해서 Exception이 발생하면 끝을 내는 방식이다 위 코드를 아래처럼 표준적인 관용구로 작성하면 다른 개발자가 바로 이해할 것이다 for (Mountain m : range) m.climb(); 그렇다면 왜 예외를 써서 반복문을 빠져나오게 했을까? 잘못된 추론을 근거로 성능을 높이려고 한 것이다 JVM은 배열에 접근할 때마다 경계를 넘지 않는지 검사하는데 일반적인 반복문도 배열 경계에 도달하면 종료한다 따라서 이 검사를 반복문에도 명시하면 중복되는 행위를 하는것이니 생략한것인데 이건 잘못된 추론이다 1. 예외는 예외 상황에 쓸 용도로 설계 되어서 JVM 개발자는 명확한 검사만큼 빠르게 만들어야 할 이유가 적다(최적화가 제대로 안됐을 가능성이 높음) 2. 코드를 try-catch 블록 안에 넣으면 JVM이 적용할 수 있는 최적화가 제한된다 3. 배열을 순회하는 표준 관용구는 앞서 걱정한 중복 검사를 수행하지 않는다 (JVM이 알아서 최적화해 없애준다) 실제로 예외를 사용한 코드가 표준 관용구보다 훨씬 느리다
예외를 사용한 반복문의 문제는 코드를 헷갈리게 하며 성능 저하를 일으키는게 끝이 아니고 제대로 동작하지 않을 수도 있다
- 반복문 안에 버그가 숨어 있다면 흐름 제어에 쓰인 예외가 이 버그를 숨겨 디버깅을 훨씬 어렵게 할 것이다
- 반복문 몸체에서 호출한 메서드가 내부에서 관련 없는 배열을 사용하다가 ArrayIndexOutOfBoundsException 을 일으켰다고 가정해보자
- 표준 관용구면 이 버그는 예외를 잡지 않고 스택 추적 정보를 남긴 후 바로 해당 스레드를 종료 시킬 것이다
- 반면 예외를 사용한 반복문은 버그 때문에 발생한 엉뚱한 예외를 정상적인 반복문 종료 상황으로 오해하고 넘어간다
위 예제에서 보았듯이 예외는 오직 예외 상황에서만 써야 한며 절대 일상적인 제어 흐름용으로 쓰여선 안 된다
- 표준적이고 쉽게 이해되는 관용구를 사용하고 성능 개선을 목적으로 과하게 머리 쓴 기법은 자제하자
- 실제로 성능이 좋아지는 경우도 있겠지만 자바 플랫폼이 꾸준히 개선되는걸 생각하면 최적화로 인한 성능 향상이 오래 가지 않을 수도 있다
- 또한 과하게 영리한 기법에 숨겨진 미묘한 버그의 폐해와 어려워진 유지보수 문제는 계속 이어질 것이다
API 설계도 적용되는 원칙이다 잘 설계된 API라면 클라이언트가 정상적인 제어 흐름에서 예외를 사용할 일이 없게 해야 한다
- 특정 상태에서만 호출할 수 있는 상태 의존적 메서드를 제공하는 클래스는 상태 검사 메서드도 함께 제공해야 한다
- Iterator 인터페이스의 next와 hasNext가 각각 상태 의존적 메서드와 상태 검사 메서드에 해당한다
- 별도의 상태 검사 메서드 덕분에 다음과 같은 표준 for 관용구를 사용할 수 있다
상태 검사 메서드, 옵셔널, 특정 값 중 하나를 선택하는 지침
- 외부 동기화 없이 여러 스레드가 동시에 접근할 수 있거나 외부 요인으로 상태가 변할 수 있다면 옵셔널이나 특정 값을 사용한다
- 상태 검사 메서드와 상태 의존적 메서드 호출 사이에 객체의 상태가 변할 수 있기 때문
- 성능이 중요한 상황에서 상태 검사 메서드가 상태 의존적 메서드의 작업 일부를 중복 수행한다면 옵셔널이나 특정 값을 선택한다
- 다른 모든 경우엔 상태 검사 메서드 방식이 조금 더 낫다
- 가독성이 살짝 더 좋으면 잘못 사용했을 때 발견하기 쉽다
- 상태 검사 메서드 호출을 깜빡 잊었다면 상태 의존적 메서드가 예외를 던져 버그를 확실히 드러낼 것이다
- 반면 특정 값은 검사하지 않고 지나쳐도 발견하기가 어렵다(옵셔널은 상관없다)
예외는 예외 상황에서 쓸 의도로 설계되었으니 정상적인 제어 흐름에서 사용해선 안되며 이를 개발자에게 강요하는 API를 만들어서도 안된다
'책 > 이펙티브 자바' 카테고리의 다른 글
item 71 필요 없는 검사 예외 사용은 피하라 (0) 2022.04.22 item 70 복구할 수 있는 상황에는 검사 예외를, 프로그래밍 오류에는 런타임 예외를 사용하라 (0) 2022.04.22 item 68 일반적으로 통용되는 명명 규칙을 따르라 (0) 2022.04.22 item 67 최적화는 신중히 하라 (0) 2022.04.22 item 66 네이티브 메서드는 신중히 사용하라 (0) 2022.04.21