>  Q&A  >  본문

为什么java不要在foreach循环里进行元素的remove/add操作


选自《阿里巴巴JAVA开发手册》

图1代码执行情况是:解释删除1这个元素不会报错,但是删除2这个元素报错了,这个情况如何解释?

PHPzPHPz2765일 전1171

모든 응답(8)나는 대답할 것이다

  • 大家讲道理

    大家讲道理2017-04-18 10:56:42

    오류의 원인 checkForComodification() 은 보고된 오류에서 알 수 있습니다. 오류를 방지하려면 modCount != expectedModCount false 로 유지해야 합니다.
    list.remove(Object)에서는 fastRemove(int) 메소드를 호출하게 되는데, 이때 불가피하게 modCount을 수정하게 되는데 이때 오류가 발생하게 됩니다.
    Iterator<String> iterator = list.iterator() ; 이 메소드의 구현은 내부 클래스 Itr(이 클래스는 반복 프로세스에서 사용됨)를 반환하는 것이지만, 이 iterator.remove()가 오류를 일으키지 않는 이유는 이 메소드 간의 관계 때문입니다. 그리고 실제 ArrayList.this.remove을 하기 전에 checkForComodfication를 확인하고 remove 뒤에 expectedModCount = modCount을 만들어서 오류가 발생하지 않도록 구현하는 것입니다.

    Itr.remove구현

    으아아아

    잘못된 점이 있으면 지적해주세요 @ChaCha哥 @puliuyinyi

    회신하다
    0
  • PHP中文网

    PHP中文网2017-04-18 10:56:42

    싱글 쓰레드의 경우 List 순회 시 요소 삭제 시 List의 Remove 메소드 대신 Iterator의 Remove 메소드를 사용해야 하며, 그렇지 않으면 ConcurrentModificationException이 발생합니다. 선생님이 학급 전체의 학생 수를 세고 있는데, 학생들이 규칙을 따르지 않고 나가고 들어오면 선생님은 확실히 그 숫자를 셀 수 없을 것이라고 상상해 보세요.

    멀티스레딩의 경우 제 블로그 중 하나를 참고해주세요: http://xxgblog.com/2016/04/02...

    회신하다
    0
  • 天蓬老师

    天蓬老师2017-04-18 10:56:42

    우선 여기에는 다중 스레드 작업이 포함됩니다. Iterator는 다중 스레드 작업을 지원하지 않습니다. List 클래스는 수정 횟수를 기록하기 위해 내부적으로 modCount 변수를 유지합니다.
    예: ArrayList 소스 코드

    으아아아

    Iterator가 생성될 때마다 Iterator는 modCount를 기록합니다. next() 메서드가 호출될 때마다 레코드는 외부 클래스 List의 modCount와 비교됩니다. 다중 스레드 편집 예외가 발생합니다.

    왜 이러는 걸까요? 내가 이해한 바에 따르면, 탐색할 컬렉션의 콘텐츠와 밀접하게 결합된 반복자를 생성했는데, 이는 이 반복기에 해당하는 컬렉션의 콘텐츠가 현재 콘텐츠라는 것을 의미합니다. 버블 정렬이 실행될 때 여전히 내 컬렉션에 데이터를 삽입하는 스레드가 있습니다. 그렇죠? 따라서 Java는 순회 중에 컬렉션이 수정되는 것을 방지하기 위해 이 간단한 처리 메커니즘을 사용합니다.

    "1"을 삭제해도 괜찮은 이유는 foreach 및 iterator의 hasNext() 메서드에 있습니다. 실제로 foreach의 구문 설탕은

    입니다. 으아아아

    따라서 모든 루프는 hasNext()를 먼저 실행하므로 ArrayList의 hasNext()가 어떻게 작성되는지 살펴보세요.

    으아아아

    cursor는 반복자의 위치를 ​​표시하는 데 사용되는 변수입니다. 변수는 0부터 시작하여 next가 호출될 때마다 +1 연산을 수행합니다.
    코드가 "1"을 삭제한 후 size=1, 커서 =1, 이때 hasNext()는 false를 반환하고 루프를 종료하므로 반복자가 두 번째 요소를 찾기 위해 next를 호출하지 않으므로 modCount를 감지할 방법이 없으므로 멀티 스레드 수정 예외가 발생하지 않습니다. 🎜> 그런데 "2"를 삭제하면 iterator가 next를 두 번 호출했는데 이때 size=1,cursor=2, hasNext()가 true를 반환했기 때문에 Iterator는 어리석게도 next()를 다시 호출하여 If도 발생했습니다. modCount가 동일하지 않으면 다중 스레드 수정 예외가 발생합니다.

    세트에 세 개의 요소가 있는 경우 "1"을 삭제하면 예외가 발생하지만 "2"를 삭제하면 문제가 발생하지 않는 이유는 위 프로그램의 실행과 관련이 있습니다. 순서는 일관됩니다.

    회신하다
    0
  • 黄舟

    黄舟2017-04-18 10:56:42

    요소를 추가하거나 삭제하면 컬렉션의 번호가 변경되므로 순회 시 문제가 발생할 수 있습니다. 예를 들어 컬렉션에 요소가 10개 있으면 요소를 추가하거나 삭제할 경우 10번 순회해야 합니다. 순회 횟수가 정확하지 않아 오류가 보고됩니다

    회신하다
    0
  • PHPz

    PHPz2017-04-18 10:56:42

    역순으로 삭제하세요. 어쨌든 목록을 삭제하지 마세요. 삭제 태그를 추가할 수 있습니다

    회신하다
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-18 10:56:42

    문서에 있는 노란색 설명이 매우 흥미롭습니다.

    이 예제의 실행 결과는 모든 사람의 예상을 뛰어넘을 것입니다. 따라서 "1"을 "2"로 바꾸면 동일한 결과가 나올까요?

    이에 대해서는 ArrayList의 소스코드를 살펴봐야 한눈에 알 수 있습니다.

    회신하다
    0
  • 巴扎黑

    巴扎黑2017-04-18 10:56:42

    역순으로 삭제하면 됩니다

    회신하다
    0
  • PHP中文网

    PHP中文网2017-04-18 10:56:42

    ArrayList는 스레드로부터 안전하지 않습니다. 즉, 순회하는 동안 목록을 수정한다는 의미입니다.
    이 경우 ArrayList는 동시 수정 예외를 발생시킵니다.

    회신하다
    0
  • 취소회신하다