> Hello World !!!

     

@syaku

Effective Java Exception : 9장 예외

Effective Java Exception : 9장 예외

57. 예외는 예외적인 상황에만 사용하라.

예외는 예외적인 상황에만 사용해야 한다. 평상시 제어흐름(ordinary control flow)에 이용해서는 안된다. 이 글은 리팩토링에서도 찾아볼 수 있다.

내용에 포함된 코드와 다른 예제를 준비해봤다.

String[] text = new String[]{ "가", "나", null, "다", "라" };

try {
    for (String str : text) {
        if (str == null) throw new Exception();
        System.out.println(str);
    }
} catch (Exception e) {
}

위 코드는 null 을 만나면 반복문 즉 순환문을 더 이상 진행하지 말고 바로 중지하려는 코드이다.

이번 쳅터에서 강조하는 말 처럼 제어흐름을 예외로 사용하지 말라는 것 인데... 위 예제소스는 예외를 이용하여 제어흐름을 조작했다. 이런식에 코드는 좋지 않다. 그리고 throw new Exception 을 사용하는 것도 좋지 않다. 대신 IllegalArgumentException 사용하는 것이 좋을 것 같다.

반복문을 종료하려면 break 사용하면 된다. return 을 사용할 수도 있다. 하지만 return for만 종료하는 것이 아니라 해당 메소드를 종료시킨다. 좋은 방법은 아니다.

추가 설명

  • 순환문: for, for-each, while, do while
  • 배열을 순회하는 표준 숙어(standard idiom) 는 for 와 같은 즉 순환문을 의미하는 것 같다. 내용 일부에서 표준적 for 숙어라는 내용이 있다.
  • 상태 종속적(state-dependent) 메서드 는 iterator  next
  • 상태 검사 메서드 는 iterator  hasNext

58. 복구 가능 상태에는 점검지정 예외를 사용하고, 프로그래밍 오류에는 실행시점 예외를 이용하라.

자바에서 3가지 'throwable' 는 점검지정 예외 'checked exception', 실행시점 예외 'runtime exception' 그리고 오류 'error'

복구 가능한 상태에는 점검지정 예외를 사용하고, 프로그래밍 오류를 나타내고 싶을 때는 실행시점 예외를 사용하라.

참고 자료 : http://www.nextree.co.kr/p3239

'Checked Exception' 는 'RuntimeException' 자식을 제외한 모두이고, 'Unchecked Exception' 는 'RuntimeException' 자식들이다.

59. 불필요한 점검지정 예외 사용은 피하라.

점검지정 예외는 코드를 반환하는 것과는 달라, 프로그래머로 하여금 예외적인 상황을 처리하도록 강제함으로써 안정성을 높인다. 너무 남발하면 사용하기 불편한 'API'가 될 수도 있다는 뜻이기도 하다.

'API'를 제대로 이용해도 예외 상황이 벌어지는 것을 막을 수 없을 때, 그리고 'API' 사용자가 예외 상황에 대한 조치를 취할 수 있을 때는, 그 정도의 부담은 참을 수있을 것이다. 하지만 이 조건 가운데 어디에도 해당되지 않을 때는 무점검 예외를 이용하는 것이 좋다.

60. 표준 예외를 사용하라.

61. 추상화 수준에 맞는 예외를 던져라.

상위 계층에서는 하위 계층에서 발생하는 예외를 반드시 받아서 상위 계층 추상화 수준에 맞는 예외로 바꿔서 던저야 한다. 이 숙어를 예외 변환 (exception translation) 이라 부른다.

public E get(int index) {
    ListIterator<E> i = listIterator(index);
    try {
        return i.next();
    } catch (NoSuchElementException e) {
        throw new IndexOutOfBoundsExceptin(...);
    }
  • NoSuchElementException : 더 이상 다음 요소를 제공하지 않을 때.
  • IndexOutOfBoundsExceptin : 인자로 주어진 첨자가 허용 범위를 벗어났을 때.

예외 연결 (exception chaining) 은 하위 계층 예외는 상위 계층 예외로 전달되는 데, 상위 계층 예외에 있는 접근자 메서드 (Throwable.getCause) 를 호출하면 해당정보를 꺼낼 수 있다.

// 예외 연결
try {
} catch (LowLevelException cause) {
    throw new HigherLevelException(cause);
}

참고 자료: http://iilii.egloos.com/4709173

아무 생각 없이 아래 계층에서 생긴 예외를 밖으로 전달하기만 하는 것보다야 예외 변환 기법이 낫지만, 남용하면 안 된다. 가능하다면 제일 좋은 방법은 하위 계층에서 예외가 생기지 않도록 한는 것이다. 하위 계층 메서드가 예외 없이 수행될 수 있도록 하는 것이다. 하위 계층 메서드에 인자를 전달하기 전에 인자 유효성을 미리 검사하는 것도 한 방법이다.

62. 메서드에서 던져지는 모든 예외에 대해 문서를 남겨라.

63. 어떤 오류인지를 드러내는 정보를 상세한 메시지에 담아라.

64. 실패 원자성 달성을 위해 노력하라.

메서드 호출이 정상적으로 처리되지 못한 객체의 상태는, 메서드 호출 전 상태와 동일해야 한다. 이 속성을 만족하는 메서드는 실패 원자성 (failure atomicity) 을 갖추었다고 한다.

실패 원자성을 달성하는 방법은 여러 가지다. 가장 간단한 방법은 변경 불가능 객체로 설계하는 것이다.

명실할 규칙은, 메서드 명세에 포함된 예외가 발생하더라도 객체 상태는 메서드 호출 이전과 동일하게 유지되어야 한다는 것이다.

원자성이란?

  • 더 이상 쪼개질 수 없는 성질
  • 더 이상 나누어 질 수 없는 하나의 행위
  • 수행 도중 중단될 수 없는 하나의 동작 단위
  • 트랜잭션의 성질 중 하나
  • 완전하게 진행되어 종료되거나, 그럴 수 없는 경우 실행을 하지 않음
  • 작업이 정상완료되지 않으면 작업을 하지 않은 상태로 원상복구됨

출처 제타위키 https://zetawiki.com/wiki/%EC%9B%90%EC%9E%90%EC%84%B1

이팩티브 자바의 일부 내용에서는 자바 언어 명세에는 long이나 double이 아닌 모든 변수는 원자적으로 읽고 쓸 수 있다고 되어 있다. [JSL-17.4.7] 다시 말해 변수를 읽으면 나오는 값은 항상 어떤 스레드가 저장한 값이라는 것 이다.

자바에서 읽고 쓰기는 원자성을 보장한다라는 말은 읽고 쓰기를 나눠서 하지 않고 한번에 한다는 말이다.

그리고 long 과 double 은 원자성을 보장하지 않다라고 JSL-17.7 되어 있다.

해당 타입은 읽고 쓰기를 32비트식 나눠 처리하기 때문에 비원장성이라고 하는 데.

재현을 해보려고 했으나... 안되더라... 안되는 건가... ㅡㅡ;;

원자성을 보장하기 위해서 AtomicLong or volatile 를 사용한다.

아래 내용을 참고하였다.

https://dzone.com/articles/longdouble-are-not-atomic-in-java
http://mygumi.tistory.com/111

65. 예외를 무시하지 마라.

예외가 바깥쪽으로 나가도록 그저 놓아두기만 해도, 적어도 프로그램이 오류가 발생한 즉시 종료되도록 만들 수 있다. 나중에 디버깅하는 데 써먹을 정보는 유지하면서 말이다.