IllegalArgumentException
가장 많이 사용되는 예외 중 하나로 호출자가 인수로 부적절한 값을 넘길 때 던지는 예외이다. 예를 들어 정수 파라미터를 받고 양수만 들어와야 한다고 할 때 음수가 들어오면 사용할 수 있다.
public void onlyPlus(int number) {
if (number <= 0) {
throw new IllegalArgumentException();
}
// ...
}
IllegalStateException
IllegalStateException도 자주 쓰이는 예외이다. 이 예외는 객체의 상태가 호출된 메서드를 수행하기에 적합하지 않을 때 주로 던진다. 예를 들어 저장된 모든 요소를 불러오는 메서드를 실행하는데 요소들이 비어있는 경우 사용할 수 있다.
public List<Element> findAll() {
if (elements.isEmpty()) {
throw new IllegalStateException();
}
return elements;
}
헷갈리는 상황?
한 번씩 IllegalArgumentException과 IllegalStateException 중 뭘 써야 하나 고민스러울 때가 있다. 설명만 보면 언제 뭘 써야 할지 명확하게 알 수 있을 것 같은데 예외가 터지는 상황을 어떻게 바라보느냐에 따라 헷갈릴 수도 있다고 생각한다.
public class Ready extends GameState {
// ...
@Override
public GameState proceed(Command command) {
if (command.isMove()) {
throw new IllegalArgumentException(CANNOT_MOVE); // 인자가 잘못?
}
if (command.isStart()) {
return new RunningWhiteTurn(board.getPieces());
}
if (command.isStatus()) {
throw new IllegalStateException(CANNOT_GENERATE_SCORE); // 객체 상태가 잘못?
}
return new Finished(board.getPieces());
}
// ...
}
위 메서드는 상태 패턴을 적용한 객체에서 Command라는 직접 정의한 인터페이스를 받아 특정 동작을 실행하는 메서드이다. GameState 하위에는 여러 상태들이 있고 각 상태가 실행시킬 수 있는 Command도 Command 구현체에 따라 다르다.
위 예에서는 Ready 상태가 Move Command와 Status Command는 실행하지 못하고 오직 Start Command만 실행할 수 있음을 보여준다.
이 상화에서 어떤 예외를 던져야할까?
IllegalArgumentException이라고 여겨지는 부분
Ready 객체 입장에서는 Start 구현체인 Command만이 적절한 인자이고 나머지는 부적절한 인자이기 때문에 IllegalArgumentException을 던지는 것이 맞다고 생각된다.
IllegalStateException이라고 여겨지는 부분
Ready 객체의 proceed 메서드는 Command 타입의 인수를 받는 것 자체는 타당하다. 허나 GameState가 현재 Ready 상태이기 때문에 Start 이외에는 실행할 수 없는 상태다. 따라서 인자의 잘못이 아닌 객체가 메서드를 호출하기에 부적절한 상태라 IllegalStateException을 던져야 한다.
이펙티브 자바에서의 설명
이펙티브 자바 아이템 72 '표준 예외를 사용하라'에서도 이 두 가지가 헷갈릴 수 있음을 설명한다. 예를 들어 카드 덱에서 인수만큼 카드를 반환해야 할 때 인수보다 적게 카드가 남아 있으면 이게 인수의 문제인지 카드의 상태 문제인지 선택하기 어렵다는 것이다.
public List<Card> getCards(int count) {
if (cards.size() < count) {
throw new ???
}
// ...
}
이에 대해 일반적인 규칙을 다음과 같이 설명하고 있다.
인수 값이 무엇이었든 어차피 실패했을 거라면 IllegalStateException을, 그렇지 않다면 IlegalArgumentException을 던지자
결론
위의 규칙에 의하면 getCards()는 카드 수보다 적은 인수가 들어오면 성공하기 때문에 IllegalArgumentException이 적절할 것이다.
그리고 Command를 받아 실행되는 proceed 메서드 또한 적절한 Command 구현체가 들어오면 예외는 발생하지 않기 때문에 IllegalArgumentException이 적절하다.
'JAVA' 카테고리의 다른 글
테스트 더블(Test Double) (0) | 2022.04.09 |
---|---|
상태 패턴 (in 체스 미션) (0) | 2022.04.04 |
[JAVA] Enum으로 if문 제거하기 (0) | 2022.03.16 |
옵저버 패턴(Observer Pattern) 살펴보기 (0) | 2022.03.05 |
[AssertJ] Iterable and array assertions 활용 (컬렉션 테스트) (0) | 2022.03.03 |