[항해99 취업 리부트 코스 학습일지] ConcurrentModificationException

HEUKWU·2024년 4월 11일
0

ConcurrentModificationException
이 예외는 객체의 동시 수정을 감지한 메서드에서 해당 수정이 허용되지 않는 경우 발생할 수 있다.

https://docs.oracle.com/javase/8/docs/api/java/util/ConcurrentModificationException.html

보통 반복문을 통해 컬렉션을 탐색하는 도중 해당 컬렉션을 수정하면 발생하는 예외이다.

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();
	}
}

항해99 취업 리부트 코스를 수강하고 작성한 콘텐츠 입니다.

항해 리부트 코스

0개의 댓글

관련 채용 정보