질문
다른 컬렉션의 내용을 기반으로 Java 모음에서 첫 번째 컬렉션에서 지정되지 않은 요소를 제거해야합니다. 이것은 매우 간단 해 보이지만 문제입니다.
이것은 내가 쓰고 싶은 방법의 헤드입니다.
Private void ScreenBlackNamelist (List <sharedboardsmswrapper> 소스, List <blacknamelistModel> BlackNamelist)
이것이 상황입니다. 소스 컬렉션은 일부 디스플레이 데이터 요소를 저장합니다. BlackNamelist Collection은 블랙리스트 목록을 저장합니다. 블랙리스트 테이블을 기반으로 소스 컬렉션에서 블랙리스트 사용자의 데이터를 제거해야합니다.
이 문제에 대한 해결책은 매우 간단해 보입니다.
먼저 각 문자마다 삭제합니다.
for (sharedboardsmswrapper tmpsharedboardsmswrapper : source) {for (blacknamelistmodel tmpblacknamelistmodel : blacknamelist) {if (tmpsharedboardsmswrapper.getSource (). 소스. 부서지다; }}}아주 간단한 질문! 나는 비밀리에 웃었다.
시험…
이 코드가 실제로 예외를 던졌다는 것이 놀랍습니다.
java.util.ConcurrentModificationException。
jdk6 매뉴얼보기
공개 클래스 동시 공동 변환 exceptionextends runtimeexception
이 예외는 메소드가 물체의 동시 수정을 감지하지만 그러한 수정을 허용하지 않을 때 발생합니다.
예를 들어, 스레드가 컬렉션 에 반복되면 다른 컬렉션이 선형 수정을 할 수 없습니다. 일반적 으로이 경우 반복 결과는 불확실합니다. 이 동작이 감지되면 일부 반복자 구현 (JRE가 제공 한 모든 일반적인 수집 구현 포함) 에서이 예외를 던질 수 있습니다. 이 작업을 수행하는 반복기를 빠른 실패 반복기라고합니다. 반복자는 향후 임의의 불확실한 행동의 위험을 위험에 빠뜨리지 않으면 서 반복자가 매우 빠르게 실패하기 때문입니다.
이 예외가 항상 다른 스레드에 의해 객체가 동시에 수정되었음을 나타내는 것은 아닙니다. 단일 스레드가 객체의 계약을 위반하는 일련의 메소드 호출을 발행하면 객체 가이 예외를 던질 수 있습니다. 예를 들어, 스레드가 빠른 실패 반복기를 사용하여 컬렉션 에서 반복 할 때 스레드가 컬렉션 을 직접 수정하면 반복자 가이 예외를 던집니다.
반복자의 빠른 고장 거동은 보장 될 수 없습니다. 일반적으로 동기가 부족한 동시 수정이 있는지 여부에 대한 어려운 보장이 불가능하기 때문입니다. 빠른 고장 작업은 ConcurrentModificationException 던지기 위해 최선을 다할 것입니다. 따라서 이러한 작업의 정확성을 향상시키기 위해이 예외에 의존하는 프로그램을 작성하는 것은 잘못입니다. 올바른 방법은 다음과 같습니다 . ConcurrentModificationException 버그를 감지하기 위해서만 사용해야합니다.
Java의 For each 실제로 처리를 위해 반복기를 사용합니다. 반복자를 사용하면 반복자를 사용하는 동안 컬렉션을 삭제할 수 없습니다. 그리고 내가 for each 참여했을 때, 나는 컬렉션에서 요소를 삭제하여 반복자가 ConcurrentModificationException 던졌습니다.
정직하게 루프를 위해 전통을 사용할 수있는 것 같습니다!
for (int i = 0; i <source.size (); i ++) {sharedboardsmswrapper tmpsharedboardsmswrapper = source.get (i); for (int j = 0; if (tmpsharedboardsmswrapper.getSource (). equals (tmpblacknamelistmodel.getSource ())) {source.remove (tmpsharedboardsmswrapper); 부서지다; }}}이제 괜찮을 것입니다! 자신감으로 테스트를 누르십시오 ...
희미한! 무슨 일이야? 데이터를 어떻게 필터링 할 수 있습니까?
디버그 추적 후 세트가 요소를 삭제하면 세트의 크기가 작아지고 인덱스가 변경되는 것으로 나타났습니다!
어떻게해야하나요? 나는 그런 작은 문제로 인해 무력하지 않을 것입니다!
Ierator를 사용하여 수집에서 요소를 삭제하십시오
JDK 매뉴얼의 반복자 인터페이스를 확인하고 제거 메소드도 있는지 확인하십시오.
제거하다
void remove ()
반복자 가 반복자가 반복하는 마지막 요소를 반복자 (선택적 작동)로 제거하십시오. 이 방법은 다음에 전화 당 한 번만 호출 할 수 있습니다. 반복자 가이 방법을 호출하는 것 외에 다른 방법을 사용하여 반복자가 가리키는 컬렉션 으로 수정되면 반복자의 동작은 불확실합니다.
던지다:
UnsupportedOperationException 반복자가 제거 작업을 지원하지 않는 경우.
IllegalStateException exception- 다음 메소드가 호출되지 않았거나 다음 메소드를 마지막으로 호출 한 후에 제거 메소드가 호출 된 경우.
최종 코드 수정 :
/ ** *@paramsource *@paramblacknamelist */ privatevoid screenblacknamelist (list <sharedboardsmswrapper> 소스, 목록 <blacknamelistmodel> blacknamelist) {iterator <sharedboardsmswrorper> sourceit = source.iterator (); while (sourceit.hasnext ()) {sharedboardsmswrapper tmpsharedboardsmswrapper = sourceit.next (); Ierator <BlackNamelistModel> BlackNameListit = BlackNamelist.iterator (); while (blacknamelistit.hasnext ()) {blacknamelistmodel tmpblacknamelistmodel = blacknamelistit.next (); if (tmpsharedboardsmswrapper.getSource (). equals (tmpblacknamelistmodel.getSource ())) {sourceit.remove (); 부서지다; }}}}} 반복자 의 next() remove() 여러 번 호출 할 수 없습니다. 그렇지 않으면 예외가 발생합니다.
컬렉션에서 요소를 삭제하는 가장 쉬운 방법은 iterator 의 remove() 메소드를 사용하는 것 같습니다!
ArrayList 클래스에서 제공 한 반복자가 어떻게 구현되는지 살펴 보겠습니다.
PrivateClass ITR은 반복자 <e> { /**를 구현합니다. 이것은 요소의 색인으로, 포인터 또는 커서와 동일하며이를 사용하여 목록의 데이터 요소에 액세스합니다. *INDEXOFELENMETTOBERETURNEDBYSUBERTCALLTONEXT. */ intcursor = 0; /** *indexofelementErternEdBymoStrecentCalltOnextor *이전. resetto -1ifthislementisdeletedByacall *toremove. 最新元素的索引。 요소가 삭제 된 경우 -1 */ intlastret = -1로 설정; /** 외부 클래스 Arraylist의 속성 : 보호 된 과도 int modcount = 0; 배열리스트가 다른 스레드에 의해 동시에 수정되고 있는지 관찰하는 데 사용됩니다. 일관성이 없다면 동기 예외가 발생합니다. *ThemodCountValuethatteitatorbelievesthathatebacking *Listshoudehave. 이 기대치가 발산되면 Theiterator *는 ConcurrentModification을 측정합니다. */intexpectedModCount = modCount; // 커서가 목록의 크기에 도달하지 않으면 여전히 요소가 있습니다. publicboolean hasnext () {returnCursor! = size (); } // 현재 요소를 반환 한 다음 커서 +1. 최근 색인 = 반환 된 요소의 색인. public e next () {checkforcomodification (); {e next = get (cursor); lastret = 커서 ++; 다음으로 돌아갑니다. } catch (indexOutOfBoundSexection e) {checkforcomodification (); 던진 nosuchelementexception (); }}/*요소를 삭제합니다. 즉, 현재 요소를 삭제하고 커서 -1을 넣는 것을 의미합니다. 목록은 다음 모든 요소를 이전 요소로 옮기기 때문입니다. */ publicVoid remove () {if (lastret == -1) 불법 스테이트 exception (); CheckforComodification (); try {acpractList.this.remove (lastret); if (lastret <cursor) 커서-; lastret = -1; 예상 modCount = modCount; } catch (indexOutOfBoundSexception e) {동시 동의어를 던지는 동시에 버린다. }} finalVoid checkforComodification () {if (modCount! = excliteModCount) 동시 모드 화가 exception (); }}요약
보시다시피, 반복자는 요소를 삭제하고 커서를 올바른 시트로 재설정합니다. 다른 스레드가 동시에 세트를 변경하지 않는 한 문제가 없습니다. 위의 내용은이 기사에 관한 모든 것입니다. 모든 사람이 Java를 배우는 것이 도움이되기를 바랍니다.