자바에서 MVC 구조를 활용한 미니 프로젝트를 진행하던 중 java.util.ConcurrentModificationException
예외가 발생했다.
에러
for (Animal animal : searchAnimals) {
if(animal.getPetId() != animalPK) {
searchAnimals.remove(animal);
}
}
에러 메시지
java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
at ubis.service.PetChargerService.getAnimalList(PetChargerService.java:75)
at ubis.controller.PetChargerController.getAnimalList(PetChargerController.java:55)
at ubis.view.StartView.main(StartView.java:79)
ConcurrentModificationException
는 동시 수정 예외로, List, Map과 같은 컬렉션을 수정하는 도중에 다른 스레드에서 동시에 컬렉션을 수정하려고 발생하는 예외이다.
수정?
- 요소를 추가(add)
- 요소를 삭제(remove)
- 컬렉션의 순서를 변경
for (Animal animal : searchAnimals) {
if(animal.getPetId() != animalPK) {
searchAnimals.remove(animal);
}
}
현재 forEach()
루프가 내부적으로 Iterator
를 사용하여 컬렉션을 반복하고 있다. Iterator는 반복하는 동안 내부에 반복자가 돌아가고 있고 중간에 다른 스레드에서 컬렉션을 수정하려고 할 때 이를 감지하고 ConcurrentModificationException을 던진다.
즉, getAnimalList 메소드에서 searchAnimals 리스트를 반복하는 동안 remove 메소드를 호출해서 이런 예외가 발생했다.
반복자(Iterator)의 안전성(safety)을 보장하기 위해서
📍 반복자의 안전성을 보장해야 하는 이유?
컬렉션의 구조적 변경은 반복자(Iterator)와의 일관성을 깨트린다.
컬렉션의 구조가 반복 중에 변경되면, 반복자의 동작이 예측할 수 없게 된다. 예를 들어, 요소가 추가되거나 삭제된 후 반복자가 어떤 요소를 반환할지 확신할 수 없다. 또한 반복 중 컬렉션의 구조가 변경되면, 잘못된 데이터를 읽어오거나 프로그램이 비정상적으로 동작할 수 있다. 그래서 애초에 ConcurrentModificationException 예외를 통해 이러한 위험을 방지한다.
즉, ConcurrentModificationException 예외는 자바 컬렉션 프레임워크가 동시 수정으로 인한 데이터 불일치를 방지하기 위해 고안된 메커니즘이라고 이해하면 된다.
1) removeIf 사용
searchAnimals.removeIf(animal -> animal.getPetId() != animalPK);
Stream API 의 removeIf
메소드를 사용하여 조건에 맞는 요소를 일괄적으로 삭제했다. 이 메소드는 내부적으로 안전하게 작업을 처리하기 때문에 에러가 발생하지 않는다.
2) Iterator 사용
Iterator<String> iterator = searchAnimals.iterator();
while (iterator.hasNext()) {
String animal = iterator.next();
if (animal.equals("Lion")) {
iterator.remove(); // Iterator의 remove 메소드 사용
}
}
Iterator의 remove() 메소드를 사용하여ConcurrentModificationException을 방지한다. 이 메소드는 반복자와 컬렉션의 상태를 일치시켜 준다.
아래는 위 에러가 발생하면서 진행했던 프로젝트이다.
MVC 구조와 Stream API를 익히고자 진행하였다.
안녕하세요~ 혹시 ld플레이어 앱 루팅우회, 애뮬레이터 우회감지를 피하고싶은데 제가 개발자가 아닌 일반인입니다. 그래서 의뢰가 가능한가해서요~
제카톡 아이디 : yit059