ConcurrentModificationException
이 예외는 객체의 동시 수정을 감지한 메서드에서 해당 수정이 허용되지 않는 경우 발생할 수 있다.
보통 반복문을 통해 컬렉션을 탐색하는 도중 해당 컬렉션을 수정하면 발생하는 예외이다.
List<String> list = new ArrayList<>();
list.add("concurrent");
list.add("modification");
list.add("exception");
for (String s : list) {
if (s.equals("exception")) {
list.remove(s);
}
}
향상된 for문을 사용해 리스트를 순회하다가 리스트의 요소를 삭제했다.
그런데 향상된 for문이 아닌 인덱스를 사용해서 똑같은 작업을 수행한다면 예외가 발생하지 않는다.
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
if (s.equals("modification")) {
list.remove(s);
}
}
이유가 뭘까.
인덱스를 사용해서 반복문을 돌다가 리스트의 요소를 삭제하면 단순히 리스트의 크기가 감소해 감소한 크기만큼 반복문을 돌다 종료한다. 리스트 크기 만큼 반복문을 돌기 때문에 리스트의 크기가 감소한 만큼 범위도 감소하기 때문에 문제가 발생하지 않는다.
하지만 향상된 for문은 내부적으로 Iterator를 사용한다. Iterator는 컬렉션의 요소를 하나씩 차례대로 반환하는 역할을 하는데 순회 도중에 컬렉션의 요소가 삭제되거나 추가되면 Iterator와 컬렌션의 상태가 동일하지 않게 된다. 따라서 예외가 발생하는 것이다.
예외를 피하기 위해서는 Iterator
를 직접 사용하는 방법이 있다. list의 .iterator()
메서드를 사용하여 Iterator
로 바꿔주고 Iterator
의 메서드를 사용해 안전하게 요소를 삭제할 수 있다.
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
if (iterator.next().equals("exception")) {
iterator.remove();
}
}