트러블 슈팅: `ConcurrentModificationException` 발생 시 해결 방법

song yuheon·2023년 10월 18일
0

Trouble Shooting

목록 보기
33/57
post-thumbnail
post-custom-banner

문제 상황


도서와 나눔 이벤트 간의 연관 관계를 삭제하는 과정에서 ConcurrentModificationException이 발생하였다.
이 오류는 컬렉션을 순회하는 동안 해당 컬렉션의 구조가 변경될 때 발생한다.


원인


bookDonationEvent.getBooks().stream().forEach(book->{
    book.changeStatus(BookStatusEnum.POSSIBLE);
    book.removeBookApplyDonation();
});

코드에서 bookDonationEvent.getBooks().forEach() 를 사용하여 도서 리스트를 순회하면서 각 도서의 상태를 변경하고 연관 관계를 제거하는 bookDonationEvent.removeBook(book)를 호출하였다.
이 때문에 순회 중인 리스트의 구조가 변경되면서 ConcurrentModificationException이 발생하였다.


해결 방법


  • 일반 for문 사용하여 해결한다.
    리스트의 크기를 미리 얻어와서 반복하는 동안 해당 리스트의 구조가 변경되지 않도록 처리할 수 있다.
    그러나 리스트의 중간 요소를 삭제할 때 인덱스의 변화를 주의해야 한다.
    이를 해결하기 위해 가장 끝부터 for문을 반복하면 해결이 가능하다.
/**
 * 연관 관계 삭제
 * 도서와 나눔 이벤트 간의 연관 관계 삭제
 */
int bookSize = bookDonationEvent.getBooks().size();
for (int i = bookSize - 1; i >= 0; i--) {
    bookDonationEvent.getBooks().get(i).changeStatus(BookStatusEnum.POSSIBLE);
    bookDonationEvent.removeBook(bookDonationEvent.getBooks().get(i));
}

/**
 * 도서와 나눔 신청 간의 연관 관계 삭제
 */
int applysize = bookDonationEvent.getBookApplyDonations().size();
for (int i = applysize - 1; i >= 0; i--) {
    Book book = bookRepository.findById(bookDonationEvent.getBookApplyDonations().get(i).getBook().getBookId()).orElseThrow(
            () -> new IllegalArgumentException("해당 책이 존재하지 않습니다.")
    );
    BookApplyDonation bookApplyDonation = bookApplyDonationRepository.findById(bookDonationEvent.getBookApplyDonations().get(i).getApplyId()).orElseThrow(
            () -> new IllegalArgumentException("해당 신청이 존재하지 않습니다.")
    );
    bookApplyDonation.removeBook(book);
    int a;
}

정리


컬렉션을 순회하면서 동시에 해당 컬렉션의 구조를 변경할 때는 ConcurrentModificationException이 발생할 위험이 있다.


profile
backend_Devloper
post-custom-banner

0개의 댓글