티스토리 뷰

예외가 발생해도 객체가 여전히 정상적으로 사용할 수 있는 상태라면
검사 예외를 던진 경우, 호출자가 오류 상태를 복구할 수 있다.

 

호출된 메서드가 실패하더라도 해당 객체는 메서드 호출 전 상태를 유지해야 한다.

이러한 특성을 실패 원자적(failure-atomic)이라고 하는데,

실패 원자적 특성을 활용하면 작업 도중 예외가 발생해도 그 객체는 여전히 정상적으로 사용할 수 있는 상태이고,

검사 예외를 던진 경우에 호출자가 오류 상태를 복구할 수 있으니 매우 유용하다.

 

💡 메서드를 실패 원자적으로 만드는 다양한 방법

첫 번째, 불변 객체로 설계한다. (가장 간단한 방법)

불변 객체는 태생적으로 실패 원자적이다.

메서드가 실패하면 새로운 객체가 만들어지지 않을 수 있으나 기존 객체가 불안정한 상태에 빠지는 일은 결코 없다.

불변 객체의 상태는 생성 시점에 고정되어 절대 변하지 않기 때문이다.

 

두 번째, 작업 수행에 앞서 매개변수의 유효성을 검사한다. (가장 흔한 방법)

객체의 내부 상태를 변경하기 전에 잠재적 예외의 가능성 대부분을 걸러낼 수 있는 방법이다.

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

또한, 실패할 가능성이 있는 모든 코드를, 객체의 상태를 바꾸는 코드보다 앞에 배치하는 방법도 있다.

 

세 번째, 객체의 임시 복사본에서 작업을 수행한 다음, 작업이 성공적으로 완료되면 원래 객체와 교체

이 방법은 데이터를 임시 자료구조에 저장해 작업하는 게 더 빠를 때 적용하지 좋다.

ex. 정렬 메서드에서 정렬을 수행하기 전에 입력 리스트의 원소들을 배열로 옮겨 담아 정렬하는 방법

 

네 번째, 작업 도중 발생하는 실패를 가로채는 복구 코드를 작성하여 작업 전 상태로 되돌리는 방법

주로 디스크 기반의 내구성을 보장해야 하는 자료구조에 쓰이는데, 자주 쓰이는 방법은 아니다.

 

❓ 항상 실패 원자적으로 만들어야 하나?

일반적으로 권장되는 덕목이지, 항상 그래야 하는 것은 아니다.

 

실패 원자적으로 만들 수 없는 경우도 있다.

예를 들어, 두 스레드가 동기화 없이 같은 객체를 동시에 수정한다면 그 객체의 일관성이 깨질 수 있다.

따라서 ConcurrentModificationException을 잡아냈다고 해서 그 객체가 여전히 쓸 수 있는 상태라고 가정하면 안 된다.

 

또한 실패 원자적으로 만들 수 있더라도 항상 그래야 하는 것도 아니다.

실패 원자성을 달성하기 위한 비용이나 복잡도가 아주 큰 연산에서는 그러지 않아도 된다.

그래도 문제가 무엇인지 알고 나면 실패 원자성을 공짜로 얻을 수 있는 경우가 많다.

 

💡 정리

메서드 명세에 기술한 예외라면 설혹 예외가 발생하더라도 객체의 상태는 메서드 호출 전과 똑같이 유지돼야 한다는 것이 기본 규칙이다.

이 규칙을 지키지 못한다면 실패 시의 객체 상태를 API 설명에 명시해야 한다.

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함