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

Loopy·2022년 12월 10일
0

이펙티브 자바

목록 보기
67/76
post-thumbnail
post-custom-banner

예외는 예외 상황에서만 써야 하지, 절대로 일상적인 제어 흐름용으로 쓰여서는 안된다. 또한, 이를 프로그래머에게 강요하는 API를 만들어서도 안된다.

제어 흐름용으로써의 사용

try {    // 성능이 2배 정도 느리다
	int i = 0;
    while(true)
    	range[i++].climb();
} catch (ArrayIndexOutOfBoundsException e) {
}

배열의 원소를 순회하는데, 무한루프를 돌다가 배열의 끝에 도달해 예외가 발생하면 끝을 내는 로직으로 작성한 코드이다. 직관적이지 않다는 점 하나만으로도 제어 흐름용으로 예외를 사용하면 안되는 이유는 충분하다.

표준적인 관용구

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

실제 예외를 사용한 쪽이 표준 관용구보다 2배 정도 느리다.

☁️ API 설계와 예외

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

1. 상태 검사 메서드

특정 상태에서만 호출할 수 있는 상태 의존적 메서드를 제공하는 클래스는, 상태 검사 메서드도 함께 제공한다면 예외를 사용하지 않을 수 있다.

Iterator 인터페이스를 예시로 들어보자. next 는 상태 의존적 메서드, hasNext 는 상태 검사 메서드에 해당한다.

// 두 메서드 덕분에 표준 for 관용구를 사용할 수 있음
for (Iterator<Foo> i = collections.iterator(); i.hasNext(); ) {
	Foo foo = i.next();
}

상태 검사 메서드를 제공하지 않은 경우

만약 IteratorhasNext 를 제공하지 않았다면 그 일을 다음과 같이 클라이언트가 대신 했어야 할 것이다.

try {
	Iterator<Foo> i = collection.iterator();
    while(true) {
    	Foo foo = i.next();
        ...
} catch (NoSuchElementException e) {
}

이처럼 반복문에 예외를 사용하면 코드가 헷갈리고 성능도 좋지 않으며, 엉뚱한 곳에서 발생한 버그를 본의 아니게 숨기기도 한다.

2. 옵셔널

상태 검사 메서드 이외에, 올바르지 않은 상태일 때 빈 Optional 혹은 null 같은 특수한 값을 반환하는 방법도 존재한다.

💡 언제 무엇을 쓰는 것이 좋을까?

  1. 외부 동기화 없이 여러 스레드가 동시에 접근할 수 있거나 외부 요인으로 상태가 변할 수 있다면 옵셔널이나 특정 값을 사용한다. 상태 검사 메서드와 상태 의존적 메서드 호출 사이에 객체의 상태가 변할 수 있기 때문이다.
  2. 성능이 중요한 상황에서 상태 검사 메서드가 상태 의존적 메서드의 작업을 일부 중복 수행한다면 옵셔널이나 특정 값을 선택한다.
  3. 다른 모든 경우엔 상태 검사 메서드 방식이 좋다. 가독성이 좋고, 잘못 사용했을 때 발견하기 쉽기 때문이다.(상태 검사 메서드 호출을 잊었다면 메서드는 예외를 던질것이다.) 옵셔널은 괜찮지만, 특정 값은 검사하지 않고 지나쳐도 발견하기 어렵다.

📚 핵심 정리
예외는 예외 상황에서 쓸 의도로 설계되었다. 정상적인 제어 흐름에서 사용해서는 안 되며, 이를 프로그래머에게 강요하는 API를 만들어서도 안 된다.

profile
개인용으로 공부하는 공간입니다. 잘못된 부분은 피드백 부탁드립니다!
post-custom-banner

0개의 댓글