엔티티의 컬렉션을 수정하려고 할 때 간혹 만났던 예외다.
이렇게 for문으로 컬렉션을 돌리면서 Collection의 원소를 삭제하려고 하니 생긴 문제다.
이게 어떻게 예외가 발생하는지 궁금해서 한번 디버깅을 해봤다.
List에서 remove를 하고서, hasNext()로 다음 원소가 있는지 확인 -> next()를 호출하는 이 부분에서 예외가 발생했다.
스택트레이스를 따라 가보면 예외는 checkFroComodification 이 메서드에서 발생한다.
modCount가 무엇인지 모르겠지만 디버깅 모드에선 4가 나오고, expectModCount는 3이라고나온다.
예외가 터지는 상황이다.
remove를 하거나 add를 할 때마다 이렇게 내부적으로 modCount를 계산하고, 변경이 된 상태라면 예외를 터뜨리는 구조로 보인다.
자바 문서 보면,
하나의 스레드가 Collection을 순회하는데 다른 스레드가 그 Collection을 변경하는 건 일반적으로 허용되지 않는다고 한다. 물론, 이 예외가 터졌다고 해서 이런 동시성 문제가 발생한다는 것은 아니다.
스레드가 하나여도 이 스레드가 Collection을 fail-fast iterator로 순회하면서 Collection을 변경하려고 하면 예외가 발생한다.
멀티 스레드 환경에서는 Concurrent 키워가 들어간 list를 쓰면 되고
지금은 Iterator를 쓰지 않으면 해결 할 수 있는 문제이다.
이번에 알게 된 사실인데 foreach는 내부적으로 iterator를 쓰고, 일반 for문을 그렇지 않다.
향상된 for문 대신 for문을 써도 되는 것이다
이렇게 스트림을 사용해서 좀더 명시적으로 표현해주었다.