diff --git "a/10\354\236\245_\354\230\210\354\231\270/item69.md" "b/10\354\236\245_\354\230\210\354\231\270/item69.md" new file mode 100644 index 0000000..206bb2e --- /dev/null +++ "b/10\354\236\245_\354\230\210\354\231\270/item69.md" @@ -0,0 +1,71 @@ +예외는 진짜 예외 상황에서만 사용해야하며 **절대 일상적인 제어 흐름용으로 사용해선 안 된다.** + +#### 예외를 잘못 사용한 코드 + +``` +try { + int i = 0; + while(true) + range[i++].climb(); +} catch (ArrayIndexOutOfBoundsException e) { + +} +``` + +위 코드는 무한 루프를 돌다가 배열의 끝에 도달해 예외가 발생하면 끝난다. +반복문에서 배열의 크기보다 커졌는지 검사를 하는 부분을 줄이려고 의도했으나, 이는 잘못된 추론이다. + +예외는 예외 상황에 쓸 용도로 설계되었으므로 JVM 구현자 입장에서는 명확한 검사만큼 빠르게 만들어야 할 만큼 최적화에 신경쓰지 않았을 확률이 높다. +코드를 try-catch 블록 안에 넣으면 JVM이 적용할 수 있는 최적화가 제한된다. +배열을 순회하는 표준 관용구는 앞서 걱정한 중복 검사를 수행하지 않는다. JVM이 알아서 최적화해서 없애준다. +즉, 코드를 헷갈리게 할 뿐만 아니라 성능을 떨어뜨리고 심지어 제대로 동작하지 않을 수도 있다. + +- 예외는 오직 예외 상황에서만 사용하라. 절대로 흐름 제어용으로 사용하면 안된다. +- 잘 설계된 API라면 클라이언트가 정상적인 제어 흐름에서 예외를 사용할 일이 없게 해야 한다. + +#### 예외 관점에서 잘 설계된 API + +잘 설계된 API는 클라이언트가 정상적인 제어 흐름에서 예외를 사용할 일이 없게 해야 한다. +특정 상태에서만 사용하는 '상태 의존적' 메소드를 제공하는 클래스는 '상태 검사' 메소드도 함께 제공해야 한다. + +예) Iterator 인터페이스의 next(상태 의존적 메소드)와 hasNext(상태 검사 메소드)를 제공한다. + +덧붙여, 별도의 상태 검사 메서드 덕분에 다음과 같은 표준 for 관용구를 사용할 수 있다.(for-each도 내부적으로 hasNext를 사용한다. + +``` + for (Iterator i = collections.iterator(); i.hasNext();) { + Foo foo = i.next(); + // ... +} +``` + +Iterator가 hasNext를 제공하지 않았다면 그 일을 클라이언트가 대신해야만 했다. + +``` +//컬렉션을 이런 식으로 순회하지 말 것! +try { + Iterator i = collection.iterator(); + while (true) { + Foo foo = i.next(); + // ... + } +} catch (NoSuchElementException e) { + +} +``` + +반복문에 예외를 사용하면 장황하고 헷갈리며 속도도 느리고, 엉뚱한 곳에서 발생한 버그를 숨기기도 한다. + +#### 상태 검사 메서드 대신 사용 가능한 선택지 + +올바르지 않은 상태일 때 빈 옵셔널(아이템 55) 혹은 null 같은 특수한 값을 반환하는 것이다. + +1. 외부 동기화 없이 여러 스레드가 동시에 접근할 수 있거나 외부 요인으로 상태가 변할 수 있다면 **옵셔널**이나 **특정 값**을 사용한다. +👉 상태 검사 메소드와 상태 의존적 메소드 호출 사이에 객체의 상태가 변할 수 있기 때문이다. +2. 성능이 중요한 상황에서 상태 검사 메서드가 상태 의존적 메소드의 작업 일부를 중복 수행한다면 **옵셔널이나 특정 값**을 사용한다. +3. 다른 경우에는 **상태 검사 메소드**를 사용하는 것이 낫다. +👉 가독성이 살짝 더 좋고, 잘못 사용했을 때 발견하기가 쉽기 때문이다. +만약 상태 검사 메서드 호출을 깜빡 잊었다면 상태 의존적 메서드가 예외를 던져 버그를 확실히 드러낼 것이다. +반면에, 특정 값은 검사하지 않고 지나쳐도 발견하기 어렵다.(옵셔널은 해당 x) + +> 예외는 예외 상황에서 쓸 의도로 설계됐다. 정상적인 제어 흐름에서 사용해선 안 되며, 이를 프로그래머에게 강요하는 API를 만들어서도 안 된다.