вопрос
Мне нужно удалить неопределенные элементы из первой коллекции из коллекции Java, основанной на содержании другой коллекции. Это выглядит очень просто, но это проблема.
Это глава метода, который я хочу написать
Private void ScreenBlackNist (список <sharedboardsmswrapper> источник, список <blacknamelistmodel> blacknamelist)
Вот как обстоят дела. Коллекция источника сохраняет некоторые элементы отображения данных. Коллекция Blacknamelist сохраняет список черных списков. Нам нужно удалить данные пользователей в черном списке в коллекции Source на основе таблицы BlackList.
Решение этой проблемы кажется очень простым.
Сначала я использую для каждого оператора для удаления.
Для (sharedboardsmswrapper tmpsharedboardsmswrapper: source) {for (blacknamelistmodel tmpblacknamelistmodel: blacknamelist) {if (tmpsharedboardsmswrapper.getsource (). Source.remove (tmpsharedboardsmswrapper); перерыв; }}}Очень простой вопрос! Я тайно смеялся,
тест…
Что меня удивило, так это то, что этот код на самом деле бросил исключение
java.util.ConcurrentModificationException。
Посмотреть руководство JDK6
public Class ComplorentModificationExceptionExtends Runtimeexception
Это исключение бросается, когда метод обнаруживает одновременную модификацию объекта, но не допускает такую модификацию.
Например, когда поток итерации на коллекции не разрешается линейно модифицировать . Обычно в этих случаях результаты итерации неясны. Если это поведение обнаружено, некоторые реализации итератора (включая все общие реализации сбора , предоставленные JRE) могут выбрать это исключение. Итератор, который выполняет эту операцию, называется итератором быстрого сбоя, потому что итератор терпит неудачу очень быстро, не рискуя риску произвольного неопределенного поведения в будущем.
Обратите внимание, что это исключение не всегда указывает на то, что объект был изменен одновременно другим потоком. Если один поток выдает последовательность вызовов метода, которая нарушает контракт объекта, объект может бросить это исключение. Например, если поток непосредственно изменяет коллекцию , когда итерация в коллекции, используя итератор Fast Fail, итератор выбросит это исключение.
Обратите внимание, что быстрое поведение итератора не может быть гарантировано, потому что, как правило, невозможно сделать какие-либо жесткие гарантии, существует ли вне синхронная одновременная модификация. Быстрая операция по сбое сделает все возможное, чтобы бросить ConcurrentModificationException . Следовательно, неправильно писать программу, которая зависит от этого исключения, чтобы улучшить правильность таких операций. Правильным способом является : ConcurrentModificationException следует использовать только для обнаружения ошибок.
For each в Java фактически используется итератор для обработки. Итератор не позволяет удалять коллекции во время использования итератора . И когда я был for each , я удалил элемент из коллекции, из -за которого итератор выбросил ConcurrentModificationException .
Кажется, что мы можем только честно использовать традиционный для цикла!
for (int i = 0; i <susion.size (); i ++) {sharedboardsmswrapper tmpsharedboardsmswrapper = source.get (i); for (int j = 0; j <blacknamelist.size (); j ++) {blacknamelistmodel tmpblacknamelistmodel = blacknamelist.get (j); if (tmpsharedboardsmswrapper.getsource (). equals (tmpblacknamelistmodel.getsource ())) {source.remove (tmpsharedboardsmswrapper); перерыв; }}}Теперь все должно быть хорошо! Нажмите на тест с уверенностью ...
слабый! Что происходит? Как данные можно отфильтровать неправильно?
После отслеживания отладки было обнаружено, что когда набор удаляет элементы, размер набора станет меньше, а индекс изменится!
Что я должен делать? Я не буду беспомощен по такой маленькой проблеме!
Используйте итератор для удаления элементов в сборе
Проверьте интерфейс итератора в руководстве JDK и увидите, что он также имеет метод удаления .
Удалять
void remove ()
Удалите последний элемент, возвращаемый итератором из коллекции , на которую указывает итератор (необязательная операция). Этот метод может быть вызван только один раз за вызов следующим образом. Если итератор изменен сбором, указывающей итератором, используя метод, отличный от вызова этого метода, поведение итератора неясно.
Бросать:
UnsupportedOperationException - если итератор не поддерживает операцию удаления .
IllegalStateException - если следующий метод не был вызван, или метод удаления был вызван после последнего вызова следующего метода.
Правильный окончательный код:
/ ** *@paramsource *@paramblacknamelist */ privatevoid screenblacknastist (list <sharedboardsmswrapper> источник, список <blacknamelistmodel> blacknamelist) {iterator <sharedboardsmswrapper> sourceit = source.iterator (); while (sourceit.hasnext ()) {sharedboardsmswrapper tmpsharedboardsmswrapper = sourceit.next (); Итератор <blacknamelistmodel> blacknamelistit = blacknamelist.iterator (); while (blacknamelistit.hasnext ()) {blacknamelistmodel tmpblacknamelistmodel = blacknamelistit.next (); if (tmpsharedboardsmswrapper.getsource (). equals (tmpblacknamelistmodel.getsource ())) {sourceit.remove (); перерыв; }}}}} Обратите внимание, что remove() итератора next() не может быть вызван несколько раз. В противном случае будет брошено исключение.
Похоже, что самый простой способ удалить элементы в коллекции - использовать метод remove() итератора !
Давайте посмотрим, как реализован итератор , предоставленный классом ArrayList .
PrivateClass ITR реализует итератор <e> { /** Это индекс элемента, который эквивалентен указателю или курсору, который использует его для доступа к элементу данных списка. *IndexoFelementToberEnteredBysubEntCallTonext. */ intcursor = 0; /** *indexofelementReturnedBymoStrecentCalltonextor *предыдущий. Resetto -1ifthiselementisdeletedbyacall *toremove. 最新元素的索引。 Если элемент был удален, установлен в -1 */ intlastret = -1; /** Свойства внешнего класса ArrayList: Защищенный Transient int modcount = 0; Он используется, чтобы наблюдать, одновременно модифицируется ArrayList в другие потоки. Если это непоследовательно, будет брошено синхронное исключение. *Themodcountvaluethattheiteratorbelievesthatthebacking *listshouldhave. Если это ожидается, Theiterator *HasdeTectedConcurrentModification. */intexpectedModCount = modCount; // Если курсор не достигает размера списка, то все еще есть элементы. publicboolean hasnext () {returncursor! = size (); } // возвращает текущий элемент, а затем курсор +1. Недавний индекс = индекс возвращаемых элементов. public e Next () {checkforComodification (); попробуйте {e next = get (cursor); lastret = cursor ++; вернуться следующим; } catch (indexoutOfBoundSexception e) {checkforComodification (); брошенная noshelementexception (); }}/*Удалить элемент, что означает удаление текущего элемента и размещение курсора-1. Потому что список переместит все следующие элементы в предыдущий. */ publicvoid remove () {if (lastret == -1) брошен allexstateException (); checkforComodification (); try {AbstractList.This.remove (lastret); if (lastret <cursor) cursor--; lastret = -1; weddcount = modcount; } catch (indexoutOfBoundSexception e) {выбрасываемой comproundModificationException (); }} finalvoid checkforComodification () {if (modcount! = weardModCount), брошенная concurrentModificationException (); }}Суммировать
Как видите, итератор удаляет элемент и сбрасывает курсор на правильное место. Пока никакие другие потоки не изменяют набор одновременно, проблем не будет. Выше приведено в этой статье, я надеюсь, что для всех будет полезно изучать Java.