pregunta
Necesito eliminar elementos no especificados de la primera colección de una colección de Java, basada en el contenido de otra colección. Esto se ve muy simple, pero es un problema.
Este es el jefe del método que quiero escribir
Private void screenblacknamelist (Lista <SharedBoardsMswrapper> Fuente, Lista <BlackNamElistModel> BlackNamelist)
Así son las cosas. La recopilación de fuente guarda algunos elementos de datos de visualización. La colección Blacknamelist guarda una lista de la lista negra. Necesitamos eliminar los datos de los usuarios en la lista negra en la colección de origen en función de la tabla de la lista negra.
La solución a este problema parece muy simple.
Primero uso el para cada declaración para eliminar.
For (SharedBoardsMSWrapper TMPSharedBoardsMswrapper: Source) {for (BlackNamElistModel TMPBlackNeMeListModel: BlacknamElsist) {if (tmpsharedboardsmswrapper.getSource (). Equals (tmpblacknamelistmodel.getSource ())) { fuente.remove (tmpsharedboardsmswrapper); romper; }}}¡Pregunta muy simple! Me reí en secreto
prueba…
Lo que me sorprendió fue que este código realmente arrojó una excepción
java.util.ConcurrentModificationException。
Ver manual JDK6
clase pública concurrentModificationExceptionExtendes runtimeException
Esta excepción se lanza cuando el método detecta la modificación concurrente del objeto, pero no permite dicha modificación.
Por ejemplo, cuando un hilo itera en una colección , no se permite que otra colección se modifique linealmente. Por lo general, en estos casos, los resultados de la iteración son inciertos. Si se detecta este comportamiento, algunas implementaciones de iterador (incluidas todas las implementaciones de colección comunes proporcionadas por JRE) pueden optar por lanzar esta excepción. El iterador que realiza esta operación se llama iterador de falla rápida porque el iterador falla muy rápidamente sin arriesgar el riesgo de un comportamiento incierto arbitrario en algún momento en el futuro.
Tenga en cuenta que esta excepción no siempre indica que el objeto ha sido modificado simultáneamente por un hilo diferente. Si un solo hilo emite una secuencia de llamadas de método que viola el contrato del objeto, el objeto puede lanzar esta excepción. Por ejemplo, si un hilo modifica directamente la colección cuando itera en la colección usando un iterador de falla rápida, el iterador lanzará esta excepción.
Tenga en cuenta que el comportamiento de falla rápida del iterador no puede garantizarse, porque en general, es imposible hacer garantías difíciles sobre si existe una modificación concurrente fuera de sincronía. Una operación de falla rápida hará todo lo posible para lanzar ConcurrentModificationException . Por lo tanto, está mal escribir un programa que depende de esta excepción para mejorar la corrección de tales operaciones. La forma correcta es : ConcurrentModificationException debe usarse solo para detectar errores.
For each en Java realmente usa Iterator para el procesamiento. El iterador no permite eliminar las colecciones durante el uso del iterador . Y cuando estaba en for each , eliminé un elemento de la colección, lo que hizo que el iterador arrojara ConcurrentModificationException .
¡Parece que solo podemos usar el tradicional para el bucle honestamente!
for (int i = 0; i <source.size (); i ++) {SharedBoardsMSWrapper TMPSharedBoardsMswraPper = Source.get (i); para (int j = 0; j <blacknamelist.size (); j ++) {blacknamelistmodel tmpblacknamelistModel = blacknamelist.get (j); if (tmpsharedboardsmswrapper.getSource (). Equals (TMPBlackNamElistModel.getSource ())) {Source.Remove (tmpsharedboardsmswrapper); romper; }}}¡Debería estar bien ahora! Presione la prueba con confianza ...
¡débil! ¿Qué está sucediendo? ¿Cómo se pueden filtrar mal los datos?
Después del seguimiento de la depuración , se descubrió que cuando el conjunto elimine los elementos, el tamaño del conjunto se volverá más pequeño y el índice cambiará.
¿Qué tengo que hacer? ¡No estaré indefenso por un problema tan pequeño!
Use Iterator para eliminar elementos en la colección
Verifique la interfaz iteradora del manual JDK y vea que también tiene un método de eliminación .
Eliminar
Vacío eliminar ()
Elimine el último elemento devuelto por el iterador del iterador apuntada por el iterador (operación opcional). Este método solo se puede llamar una vez por llamada siguiente. Si el iterador modifica el iterador mediante una colección que apunta por el iterador utilizando un método que no sea llamar a este método, el comportamiento del iterador es incierto.
Tirar:
UnsupportedOperationException : si el iterador no admite eliminar la operación.
IllegalStateException : si no se ha llamado al siguiente método, o se ha llamado al método de eliminación después de la última llamada al siguiente método.
Código final correcto:
/ ** *@paramsource *@paramblacknamelist */ privateVoid ScreenblackNamElist (List <SharedBoardsMswraPper> Fuente, Lista <BlackNeMeListModel> BlackNamElist) {Iterator <SharedBoardsMswraPpers> SourceIt = Source.iterator (); while (sourceIt.hasNext ()) {SharedBoardsMSWrapper TMPSharedBoardsMswraPper = SourceIt.Next (); Iterador <BlackNamElistModel> BlacknamElistit = BlackNamElist.iterator (); while (blacknamelistit.hasnext ()) {blacknamelistmodel tmpblacknamelistModel = blacknamelistit.next (); if (tmpsharedboardsmswrapper.getSource (). Equals (tmpblacknamelistModel.getSource ())) {sourceIt.Remove (); romper; }}}}} Tenga en cuenta que el remove() next() del iterador no se puede llamar varias veces. De lo contrario, se lanzará una excepción.
¡Parece que la forma más fácil de eliminar elementos en una colección es usar el método de iterator remove() !
Veamos cómo se implementa el iterador proporcionado por la clase ArrayList .
PrivateClass ITR implementa Iterator <E> { /** Este es el índice del elemento, que es equivalente a un puntero o cursor, que lo usa para acceder al elemento de datos de la lista. *IndexOfelementTobereturnedBysubSubeScallTonext. */ intcursor = 0; /** *IndexOfElementTurnedByMoStrecentCallTonexTor *Anterior. Resetto -1ifthIselementIsdeletedByAcall *Toremove. 最新元素的索引。 Si el elemento se ha eliminado, establecido en -1 */ intLastret = -1; /** Propiedades de la ArrayList de clase externa: transitorio protegido int modCount = 0; Se utiliza para observar si la lista de matrices está siendo modificada por otros hilos al mismo tiempo. Si es inconsistente, se lanzará una excepción sincrónica. *Themodcountvaluethattheiteratorbelievesthatthebacking *listshhove. Si esta expectativa se viola, el teiterador *ha determinado la modificación de la concurrencia. */intespectedModCount = modcount; // Si el cursor no alcanza el tamaño de la lista, entonces todavía hay elementos. publicboolean Hasnext () {returnCursor! = size (); } // Devuelve el elemento actual y luego el cursor +1. Índice reciente = índice de elementos devueltos. public e next () {checkforComodification (); intente {e next = get (cursor); Lastret = cursor ++; regresar a continuación; } Catch (indexOuTOfBoundsexception e) {checkforcomodification (); throwlew nosuchelementException (); }}/*Eliminar un elemento, lo que significa eliminar el elemento actual y poner cursor-1. Porque, la lista moverá todos los siguientes elementos al anterior. */ publicvoid remove () {if (lastret == -1) thronewew ilegalStateException (); checkforcomodification (); intente {abstractList.this.remove (Latret); if (lastret <cursor) cursor--; Lastret = -1; esperadoModCount = modCount; } Catch (indexOuTOfBoundsexception e) {throwlew concurrentModificationException (); }} FinalVoid checkForComOdification () {if (ModCount! = EsperadoModCount) thronewew concurrentModificationException (); }}Resumir
Como puede ver, el iterador elimina el elemento y restablece el cursor al asiento correcto. Mientras ningún otro hilo cambie el conjunto al mismo tiempo, no habrá ningún problema. Lo anterior se trata de este artículo, espero que sea útil para todos aprender Java.