Java에서 IllegalStateException은 대표적인 비검사(unchecked) 예외입니다. 이 예외는 주로 java.util 패키지의 컬렉션 프레임워크를 다룰 때 발생하며, List, Queue, Tree, Map 등 다양한 컬렉션 중에서도 특히 List와 Queue(Queue 및 Deque)에서 특정 조건 하에 이 예외를 던집니다.
IllegalStateException이 발생하는 상황
- 부적절한 시점에 메서드를 호출하려고 할 때 발생합니다. 즉, 객체의 현재 상태에서 허용되지 않는 작업을 수행하려는 경우입니다.
- java.util.List 컬렉션을 순회할 때는 ListIterator 인터페이스의 next() 메서드를 사용합니다. 만약 next()를 호출하기 전에 remove() 메서드를 먼저 호출하면 List 컬렉션이 불안정한(unstable) 상태에 놓이게 되어 이 예외가 발생합니다.
- 순회 중인 요소를 수정하려면 set() 메서드를 사용해야 하는데, 이 역시 반드시 next() 또는 previous() 호출 이후에만 사용할 수 있습니다. 규칙을 어기면 IllegalStateException이 발생합니다.
- Queue의 경우, 용량이 제한된 큐에 요소를 추가하기 전에는 큐가 가득 차 있지 않은지 반드시 확인해야 합니다. 가득 찬 큐에 요소를 추가하려고 하면 IllegalStateException이 발생합니다.
예제 코드
import java.util.*;
public class IllegalStateExceptionTest {
public static void main(String args[]) {
List list = new LinkedList();
list.add("Welcome");
list.add("to");
list.add("Tutorials");
list.add("Point");
ListIterator lIterator = list.listIterator();
lIterator.next();
lIterator.remove();// modifying the list
lIterator.set("Tutorix");
System.out.println(list);
}
}
실행 결과
Exception in thread "main" java.lang.IllegalStateException
at java.util.LinkedList$ListItr.set(LinkedList.java:937)
at IllegalStateExceptionTest.main(IllegalStateExceptionTest.java:15)
왜 예외가 발생했을까?
위 예제에서는 remove()를 호출한 직후 set()을 호출했습니다. ListIterator의 규약에 따르면 set()이나 remove()는 각각 next() 또는 previous() 호출 직후에 한 번만 사용할 수 있습니다. remove() 호출 후 set()을 바로 실행하면 반복자의 상태가 유효하지 않아 IllegalStateException이 발생하는 것입니다.
해결 방법
요소를 수정하려면 remove()와 set() 사이에 next()를 다시 호출하여 반복자 상태를 초기화해야 합니다.
lIterator.next();
lIterator.remove(); // 요소 삭제
lIterator.next(); // 반복자 상태 재설정
lIterator.set("Tutorix"); // 정상적으로 수정됨
이처럼 IllegalStateException은 코드 로직 오류로 인해 발생하는 런타임 예외이므로, 컴파일러가 강제하지 않더라도 컬렉션 API의 호출 순서 규약을 항상 준수하는 것이 중요합니다.