💥 개요
try {
int i = 0;
while(true) {
ranmge[i++].climb();
} catch(ArrayIndexOutOfBodundsException e) {
}
위와 같은 코드는 전혀 직관적이지 않다. 배열의 원소를 순회하는데, 아주 끔찍한 방식으로 사용하고 있다. 무한루프를 돌다가 배열의 끝에 도달해 ArrayIndexOutOfBodundsException이 발생하면 끝을 내는 것이다.
이 코드의 의도는 잘못된 추론을 근거로 성능을 높이려 했다. JVM은 배열에 접근할 때마다 경계를 넘지 않는지 검사하는데, 일반적인 반복문도 배열 경계에 도달하면 종료한다. 따라서 이 검사를 반복문에도 명시하면 같은 일이 중복되므로 하나를 생략한 것이다.
하지만 3가지 문제가 있다.
- 예외는 예외 상황에 쓸 용도로 설계되었으므로 개발자 입장에서는 명확한 검사만큼 빠르게 만들어야 할 동기가 약하다(최적화에 별로 신경쓰지 않았을 가능성이 크다.)
- 코드를 try catch 블록 안에 넣으면 JVM이 적용할 수 있는 최적화가 제한된다.
- 배열을 순회하는 표준 관용구는 앞서 걱정한 중복 검사를 수행하지 않는다. JVM이 알아서 최적화해 없애준다.
실제로 100개짜리 배열 기준으로 2배나 더 느리다.
💡예외는 오직 예외 상황에서만 써야 한다.
예외는 오직 예외 상황에서만 써야 한다. 절대로 일상적인 제어 흐름용으로 쓰여선 안 된다.
표준적이고 이해하기 쉬운 관용구를 사용하고, 성능 개선을 목적으로 과하게 머리 쓴 기법은 자제하라. 성능이 좋아지더라도 자바가 업데이트 되면서 얻은 최적화로 인해 버그가 발생하거나 성능 우위가 오래가지 않을 수 있다.
반복문에 예외를 사용하면 장황하고 헷갈리며 속도도 느리고, 엉뚱한 곳에서 버그를 숨기기도 한다.
상태 검사 메서드 대신 사용할 수 있는 선택지도 있다. 올바르지 않은 상태일 때 빈 옵셔널 혹은 null 같은 특수한 값을 반환하는 방법이다.
👍 상태검사, 옵셔널, 특정 값 중 하나를 선택하는 지침
- 외부 동기화 없이 여러 스레드가 동시에 접근할 수 있거나 외부 요인으로 상태가 변할 수 있다면 옵셔널이나 특정 값을 사용한다. 상태 검사 메서드와 상태 의존적인 메서드 호출 사이에 객체의 상태가 변할 수 있기 때문이다.
- 성능이 중요한 상황에서 상태 검사 메서드가 상태 의존적 메서드의 작업 일부를 중복 수행한다면 옵셔널이나 특정 값을 선택한다.
- 다른 모든 경우엔 상태 검사 메서드 방식이 조금 더 낫다고 할 수 있다. 가독성이 살짝 더 좋고, 잘못 사용했을 때 발견하기가 쉽다. 상태 검사 메서드 호출을 깜빡 잊었다면 상태 의존적 메서드가 예외를 던져 버그를 확실히 드러낼 것이다. 반면 특정 값은 검사하지 않고 지나쳐도 발견하기가 어렵다(옵셔널에는 해당하지 않는 문제다).
예외는 예외 상황에서 쓸 의도로 설계되었다. 정상적인 제어 흐름에서 사용해서는 안 되며, 이를 프로그래머에게 강요하는 API를 만들어서도 안 된다.
'Study > 이펙티브 자바' 카테고리의 다른 글
[Effective Java] 메서드가 던지는 모든 예외를 문서화하라 (0) | 2024.05.08 |
---|---|
[Effective Java] 복구할 수 있는 상황에는 검사 예외를, 프로그래밍 오류에는 런타임 예외를 사용하라 (1) | 2024.05.07 |
[Effective Java] 객체는 인터페이스를 사용해 참조하라 (0) | 2024.04.22 |
[Effective Java] 반환 타입으로는 스트림보다 컬렉션이 낫다 (0) | 2024.04.20 |