코드는 괜찮아 보이지만 재고 목록 내 한 supply라도 오염되었을 경우 무조건 충돌합니다. 더 큰 문제는 이 문제가 처음 발생하기 전까지는 코드가 잘 동작한다는 점입니다. 더욱이 모든 제품이 깨끗하면 문제없이 동작할 테니 버그를 발견하기 어렵고요.
문제는 supplies를 순회하는 for 루프 내 supplies.remove(supply)를 호출하는 부분입니다. 이렇게 실행하면 List 인터페이스의 표준 구현이나 Set이나 Queue와 같은 Collection 인터페이스의 구현은 ConcurrentModificationException을 던집니다. List를 순회하며 List를 수정할 수 없습니다.
단일 스레드 애플리케이션에서 동시(concurrency) 실행이라니 ConcurrentModificationException이라는 이름이 꽤 이상하게 느껴집니다. 실제로 동시 실행은 일어나지 않으니 다소 오해의 소지가 있네요! 다름 아니라 Collection을 순회하는 동안 그 컬렉션을 수정한다는 뜻입니다. 불행히도 자바의 컴파일 타임 검사로는 이 오류를 잡아내지 못 합니다.
그렇다면 ConcurrentModificationException을 일으키지 않으면서 어떻게 올바르게 수행할까요?
class Inventory { private List<Supply> supplies = new ArrayList<>(); void disposeContaminatedSupplies() { Iterator<Supply> iterator = supplies.iterator(); while (iterator.hasNext()) { if (iterator.next().isContaminated()) { iterator.remove(); } } } }