실패 원자적 성질
호출된 메서드가 실패하더라도 해당 객체는 메서드 호출 전 상태를 유지해야 한다. 이러한 특성을 실패 원자적이라고 한다.
메서드를 실패 원자적으로 만드는 방법
- 불변 객체로 설계한다.
- 메서드가 실패하면 객체가 생성되지 않을 수는 있으나 값은 생성 시점에 고정되어 절대 변하지 않는다.
- 작업 수행에 앞서 매개변수의 유효성을 검사한다.
public Object pop() {
if (size == 0) throw new EmptyStackException();
Object result = element[--size];
elements[size] = null; // 다 쓴 참조 해제
return result;
}
이 메서드는 처음 if문에서 size의 값을 확인하여 0이면 예외를 던진다. 이 부분을 제거하더라도 스택이 비어있다면 여전히 예외를 던진다. 하지만 size의 값이 음수가 되어 다음 번 호출도 실패하게 만들며, 이 때, 던지는 ArrayIndexOutOfBoundException은 추상화 수준이 상황에 어울리지 않다.
비슷한 취지로 실패할 가능성이 있는 모든 코드를, 객체의 상태를 바꾸는 코드보다 앞에 배치하는 방법도 있다.
- 객체의 임시 복사본에서 작업을 수행한 다음, 작업이 성공적으로 완료되면 원래 객체와 교체한다.
- 데이터를 임시 자료구조에 저장해 작업하는 게 더 빠를 때 적용하기 좋다.
- e.g ) 어떤 정렬 메서드에서는 정렬을 수행하기 전에 입력 리스트의 원소들을 배열로 옮겨 담는다. 배열을 사용하면 정렬 알고리즘의 반복문에서 원소들에 훨씬 빠르게 접근할 수 있다.
- 작업 도중 발생하는 실패를 가로채는 복구 코드를 작성하여 작업 전 상태로 되돌린다.
- 주로 디스크 기반의 내구성을 보장해야 하는 자료구조에 쓰이는데, 자주 쓰이지는 않는다.
한편, Error는 복구할 수 없으므로 AssertionError에 대해서는 실패 원자적으로 만들려는 시도조차 할 필요가 없다.