왜 foreach 순환 에서 JAVA 집합 은 요 소 를 추가 하거나 삭제 할 수 없 습 니까?

1.인 코딩 강제 규약
에서 집합 작업 에 대해 다음 과 같은 규정 이 있다.
[강제]있 지 마. foreach 순환 에서 원소 의 remove/add 조작remove 원소 사용 Iterator 방식,동시 다발 작업 이 필요 합 니 다. Iterator 대상 잠 금.

public class SimpleTest {
    public static void main(String[] args) {
        List<String> list = Lists.newArrayList();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
 
        //  
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String item = iterator.next();
            if ("1".equalsIgnoreCase(item)) {
                iterator.remove();
            }
        }
 
        //  
        for (String item : list) {
            if ("2".equals(item)) {
                list.remove(item);
            }
        }
    }
}
2.원인 분석
순환 하거나 교체 할 때 먼저 교체 인 스 턴 스 를 만 듭 니 다.이 교체 인 스 턴 스 의 expected ModCount 는 집합 적 인 modCount 입 니 다.   
교체 기 가 이성 hashNext()/next()를 다음 요 소 를 옮 겨 다 닐 때마다 modCount 변 수 는 expected ModCount 값 과 같 는 지,같 으 면 옮 겨 다 니 는 지 확인 합 니 다.그렇지 않 으 면 이상 을 던 집 니 다.
순환 에 요 소 를 추가 하거나 삭제 하면 집합 한 add,reove 방법[modCount 증가 또는 감소]을 직접 호출 합 니 다.그러나 이 방법 들 은 교체 인 스 턴 스 의 expected ModCount 를 수정 하지 않 고 교체 인 스 턴 스 에서 expected ModCount 와 modCount 의 값 이 같 지 않 습 니 다.Concurrent ModificationException 이상 을 던 집 니 다.
그러나 교체 기 에 있 는 reove,add 방법 은 집합 적 인 reove,add 방법 을 호출 한 후 expected ModCount 를 modCount 로 다시 할당 하기 때문에 교체 기 에 요 소 를 추가 하고 삭제 하면 정상적으로 작 동 할 수 있 습 니 다.
Array List 의 내부 개인 클래스 Itr,ListItr 의 소스 코드 를 참고 할 수 있 습 니 다.

public Iterator<E> iterator() {
        return new Itr();
    }
 
/**
     * An optimized version of AbstractList.Itr
     */
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;
 
        Itr() {}
 
        //       
 
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();
 
            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
 
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
 
  }
   public E remove(int index) {
        rangeCheck(index);
 
        modCount++;
        E oldValue = elementData(index);
 
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
 
        return oldValue;
    }
3.관련 지식 소개
3.1.빠 른 실패(fail-fast)는 무엇 입 니까?
빠 른 실패(fail-fast) 예. Java 집합 적 인 오류 검출 메커니즘.스토리 보드 가 집합 을 옮 겨 다 닐 때 다 중 스 레 드 에서 작업 할 수 있 습 니 다.안전 실패(fail-safe)의 집합 류 가 실 행 될 수 있 습 니 다. fail-fast 메커니즘,Concurrent ModificationException 던 지기 이상 하 다 
또한,단일 스 레 드 에서 옮 겨 다 니 는 과정 에서 집합 대상 의 내용 을 수정 하면 트리거 됩 니 다. fail-fast 메커니즘.
다 중 스 레 드 에서 스 레 드 가 있 으 면 1 집합 을 옮 겨 다 니 고 있 습 니 다.이 때 스 레 드 입 니 다. 2 집합 에 대한 수정(추가,삭제,수정)또는 스 레 드 1 옮 겨 다 니 는 과정 에서 집합 을 수정 하면 스 레 드 를 초래 할 수 있 습 니 다. 1 Concurrent ModificationException 던 지기 이상 하 다
3.2.안전 실패(fail-safe)는 무엇 입 니까?
스토리 보드 보안 실패 메커니즘 의 집합 용 기 를 채취 하여 옮 겨 다 닐 때 집합 내용 에 직접 접근 하 는 것 이 아 닙 니 다.따라서 옮 겨 다 니 는 과정 에서 원래 집합 에 대한 수정 은 교체 기 에 의 해 감지 되 지 않 기 때문에 Concurrent ModificationException 을 버 리 지 않 습 니 다. 이상 하 다
foreach 순환 에서 왜 JAVA 집합 이 요 소 를 추가 하거나 삭제 할 수 없 는 지 에 대한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 JAVA 집합 이 요 소 를 추가 하거나 삭제 하 는 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 도 많은 관심 을 가 져 주시 기 바 랍 니 다!

좋은 웹페이지 즐겨찾기