EffectiveJava

[EffectiveJava] 10장 예외

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

// 69-1 예외를 완전히 잘못 사용한 예 - 따라하지 말 것!
try {
    int i = 0;
    while(true) { // 절대 좋지 않은 코드
        range[i++].climb();

    }
} catch (ArrayIndexOutOfBoundsException e){

}
// 표준적인 관용구로 하면 이해하기 쉽고 try는 필요하지 않다,
for (Mountain m : range) { 
    m.climb();
}
for ( Iterator<Foo> i = collection.iterator(); i.hashNext(); ) {
  Foo foo = i.next();
	...
}
// 컬렉션을 이런 식으로 순회하지 말 것!
try {
    Iterator<Foo> i = collection.iterator();
    while (true) {
        Foo foo = i.next();
        ...
    }
} catch (NoSuchElementException e){

}

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

71. 필요 없는 검사 예외 사용은 피하라

// 검사 예외와 비검사 예외 중 어느 것을 선택해야 할지는 프로그래머가 그 예외를 어떻게 다룰지 생각해보면 알 수 있다.
} catch (TheCheckedException e) {
    throw new AssertionError(); // 일어날 수 없다!
}

} catch (TheCheckedException e) {
    e.printStackTrace(); // 이런, 우리가 졌다.
    System.exit(1);
}
// 71-1 검사 예외를 던지는 메서드 - 리팩토링 전
try {
    obj.action(args);
} catch (TheCheckedException e) {
		... // 예외 상황에 대처한다.
}
// 71-2 상태 검사 메서드와 비검사 예외를 던지는 메서드 - 리팩토링 후
if (obj.actionPermitted(args) {
		obj.action(args);
} else {
		... // 예외 상황에 대처한다.
}
obj.action(args);

72. 표준 예외를 사용하라

73. 추상화 수준에 맞는 예외를 던지라

// 73-1 예외 번역
try {
    ... // 저수준 추상화를 이용한다.
} catch (LowerLevelException e) {
    // 추상화 수준에 맞게 번역한다.
    throw new HigherLevelException();
}
/**
* 이 리스트 안의 지정한 위치의 원소를 반환한다.
* @throws IndexOutOfBoundsException index가 범위 밖이라면, 
*    즉 ({@code index < 0 || index >= size()})이면 발생한다.
*/
public E get(int index) {
    ListInterator<E> i = listInterator(index);
    try{
        return i.next();
    } catch (NoSuchElementException e) {
        throw new IndexOutOfBoundsException("인덱스: " + index);
    }
}
// 73-2 예외 연쇄
try {
    ... // 저수준 추상화를 이용한다.
} catch (LogwerLevelException cause) {
    // 저수준 예외를 고수준 예외에 실어 보낸다.
    throw new HigherLevelException(cause);
}
// 73-3 예외 연쇄용 생성자
class HigherLevelExcetion extends Exception {
    HigherLevelException(Throwable cause) {
        super(cause);
    }
}

74. 메서드가 던지는 모든 예외를 문서화하라

75. 예외의 상세 메시지에 실패 관련 정보를 담으라

/**
* IndexOutOfBoundsException을 생성한다
*
* @param lowerBound 인덱스의 최솟값
* @param upperBound 인덱스의 최댓값 + 1
* @param index 인덱스의 실젯값
*/
public IndexOutOfBoundsException(int lowerBound, int upperBound, int index){
	  // 실패를 포착하는 상세 메시지를 생성한다.
	 super(String.format(
	 	"최솟값: %d , 최댓값: %d, 인덱스: %d", 
	 	lowerBound, upperBound, index));
	 
	 // 프로그램에서 이용할 수 있도록 실패 정보를 저장해둔다.
	 this.lowerBound = lowerBound;
	 this.upperBound = upperBound;
	 this.index = index;
}

76. 가능한 한 실패 원자적으로 만들라

public Object pop() {
     **if (size == 0) 
         throw new EmptyStackException();**
     Object result = elements[--size];
     elements[size] = null; // 다 쓴 참조 해제
     return result;
 }

77. 예외를 무시하지 말라

// catch 블록을 비워두면 예외가 무시된다. 아주 의심스러운 코드다!
try {
    ...
} catch (SomeException e) {
}
Future<Integer> f = exec.submit(planarMap::chromaticNumber);
int numColors = 4; // 기본값. 어떤 지도라도 이 값이면 충분하다.
try {
    numColor = f.get(1L, TimeUnit.SECONDS);
} catch (TimeoutException | ExecutionException ignored) {
    // 기본 값을 사용한다(색상 수를 최소화하면 좋지만, 필수는 아니다).
}

Leave a Reply