pergunta
Preciso remover elementos não especificados da primeira coleção de uma coleção de Java, com base no conteúdo de outra coleção. Isso parece muito simples, mas é um problema.
Este é o chefe do método que quero escrever
private void screenblackNameList (Lista <SharedBoardsMswrapper> Fonte, Lista <BlackNameListModel> Blacknamelist)
É assim que as coisas são. A coleção de origem salva alguns elementos de dados de exibição. A coleção Blacknamelist salva uma lista de lista negra. Precisamos remover os dados de usuários na lista negra na coleção de origem com base na tabela da lista negra.
A solução para esse problema parece muito simples.
Eu primeiro uso o para cada declaração para excluir.
para (sharedboardsmswrapper tmpsharedboardsMswrapper: fonte) {for (BlackNameListModel tmpblackNameListModel: BlackNameList) {if (tmpsharedboardsmswrapper.getSource (). Equals (tmpblackNameListmodel.getSource (). source.remove (tmpsharedboardsmswrapper); quebrar; }}}Pergunta muito simples! Eu ri secretamente,
teste…
O que me surpreendeu foi que esse código realmente jogou uma exceção
java.util.ConcurrentModificationException。
Veja o manual do JDK6
Classe pública ConcurrentModificationExceptionExtends RunTimeException
Essa exceção é lançada quando o método detecta modificação simultânea do objeto, mas não permite essa modificação.
Por exemplo, quando um thread itera em uma coleção , outra coleção não pode ser modificada linearmente. Geralmente nesses casos, os resultados da iteração são incertos. Se esse comportamento for detectado, algumas implementações do iterador (incluindo todas as implementações de coleta comum fornecidas pelo JRE) poderão optar por lançar essa exceção. O iterador que executa esta operação é chamado de iterador de falha rápida porque o iterador falha muito rapidamente, sem arriscar o risco de comportamento incerto arbitrário em algum momento no futuro.
Observe que essa exceção nem sempre indica que o objeto foi modificado simultaneamente por um encadeamento diferente. Se um único thread emitir uma sequência de chamadas de método que viole o contrato do objeto, o objeto poderá lançar essa exceção. Por exemplo, se um thread modificar diretamente a coleção quando itera na coleção usando um iterador de falha rápido, o iterador lançará essa exceção.
Observe que o comportamento de falha rápida do iterador não pode ser garantida, porque geralmente é impossível fazer garantias difíceis sobre se existe uma modificação simultânea fora do síncrono. Uma operação de falha rápida fará o possível para lançar ConcurrentModificationException . Portanto, é errado escrever um programa que depende dessa exceção para melhorar a correção de tais operações. A maneira correta é : ConcurrentModificationException deve ser usado apenas para detectar erros.
For each em Java, na verdade, usa o iterador para processamento. O iterador não permite que as coleções sejam excluídas durante o uso do iterador . E quando eu estava em for each , excluí um elemento da coleção, o que fez com que o iterador jogasse ConcurrentModificationException .
Parece que só podemos usar o tradicional para o loop honestamente!
for (int i = 0; i <fonte.size (); i ++) {sharedboardsMswrapper tmpSharedBoardsMSwapper = fonte.get (i); for (int j = 0; j <BlackNameList.size (); j ++) {BlackNameListModel tmpblackNameListModel = BlackNameList.get (J); if (tmpSharedboardsMswrapper.getSource (). Iguals (tmpblackNameListModel.getSource ())) {source.Remove (tmpSharedboardsMswrapper); quebrar; }}}Deve estar bem agora! Pressione o teste com confiança ...
desmaiar! O que está acontecendo? Como os dados podem ser filtrados errados?
Após o rastreamento de depuração , verificou -se que, quando o conjunto exclui elementos, o tamanho do conjunto ficará menor e o índice mudará!
O que devo fazer? Não ficarei impotente por um problema tão pequeno!
Use o iterador para excluir elementos na coleção
Verifique a interface do iterador do manual JDK e veja que ele também possui um método de remoção .
Remover
vazio remove ()
Remova o último elemento retornado pelo iterador da coleção apontada pelo iterador (operação opcional). Este método só pode ser chamado uma vez por chamada em seguida. Se o iterador for modificado por uma coleção apontando pelo iterador usando um método diferente de chamar esse método, o comportamento do iterador será incerto.
Lançar:
UnsupportedOperationException - Se o iterador não suportar a operação Remover .
IllegalStateException - Se o próximo método não tiver sido chamado, ou o método de remoção foi chamado após a última chamada para o próximo método.
Código final correto:
/ ** *@paramSource *@LublackNameList */ PrivateVoid ScreenBlackNameList (List <SharedBoardsMswrapper> Fonte, List <BlackNameListModel> BlackNameList) {iterator <SharedBoardsMswrapper> fonte = fonte.iterator (); while (sourceit.hasNext ()) {sharedboardsMswrapper tmpSharedboardsMswrapper = sourceit.Next (); Iterador <lacknamelistmodel> BlackNameListit = BlackNameList.iterator (); while (BlackNameListit.hasNext ()) {BlackNameListModel tmpBlackNameListModel = BlackNameListit.Next (); if (tmpSharedboardsMswrapper.getSource (). Iguals (tmpblackNameListModel.getSource ())) {sourceit.remove (); quebrar; }}}}} Observe que o remove() next() do iterador não pode ser chamado várias vezes. Caso contrário, uma exceção será lançada.
Parece que a maneira mais fácil de excluir elementos em uma coleção é usar o método remove() do iterador !
Vamos ver como o iterador fornecido pela classe Arraylist é implementado.
PrivateClass ITR implementa o iterador <E> { /** Este é o índice do elemento, que é equivalente a um ponteiro ou cursor, que o usa para acessar o elemento de dados da lista. *IndexOfElementToberETurnedBySubSofEntCallTonext. */ intcursor = 0; /** *IndexOfElementRenhedByMosTreCentCalloTonextor *Anterior. Resetto -1iftisElementisDeleTEdByAcall *Toremove. 最新元素的索引。 Se o elemento foi excluído, definido como -1 */ intlastret = -1; /** Propriedades do ArrayList de classe externa: transitório protegido int modCount = 0; É usado para observar se a lista de Array está sendo modificada por outros threads ao mesmo tempo. Se for inconsistente, uma exceção síncrona será lançada. *ThemodCountValuethatheiteratorBelievesthatthebacking *listswouldhave. Se essa expectativa for violada, o teterator *hasdetectectedCurrentModification. */INTEXPICEDMODCOUNT = modCount; // Se o cursor não atingir o tamanho da lista, ainda existem elementos. publicBoolean hasNext () {returnCursor! = size (); } // retorna o elemento atual e depois cursor +1. Índice recente = índice de elementos retornados. public e next () {checkForComodification (); tente {e seguinte = get (cursor); lastret = cursor ++; retornar a seguir; } catch (indexOutOfBoundSexception e) {checkForComodification (); thrownew nosuchElementException (); }}/*Exclua um elemento, o que significa excluir o elemento atual e colocar o cursor-1. Porque, a lista moverá todos os seguintes elementos para o anterior. */ publicVoid remover () {if (lastret == -1) thrownew ilegalStateException (); checkForComodification (); tente {abstractList.this.remove (lastret); if (lastret <cursor) cursor--; lastret = -1; esperadomodCount = modCount; } catch (indexOutOfBoundSexception e) {thrownew concurrentModificationException (); }} FinalVoid checkForComodification () {if (modCount! = esperadoModCount) thrownew concurrentmodificationException (); }}Resumir
Como você pode ver, o iterador exclui o elemento e redefine o cursor para o assento correto. Desde que nenhum outro threads altere o conjunto ao mesmo tempo, não haverá problema. O exposto acima é tudo sobre este artigo, espero que seja útil para todos aprenderem Java.