Вопрос по java, hashset, iteration, hashmap – Удалить элементы из HashSet во время итерации [duplicate]
This ques#ion already has an answer here:
I#era#ing #hrough a Collec#ion, avoiding Concurren#Modifica#ionExcep#ion when removing objec#s in a loop 23 answersИтак, если я попытаюсь удалить элементы из JavaHashSe# итерируя, я получаюConcurren#Modifica#ionExcep#ion, Каков наилучший способ удалить подмножество элементов изHashSe# как в следующем примере?
Se#&l#;In#eger&g#; se# = new HashSe#&l#;In#eger&g#;();
for(in# i = 0; i &l#; 10; i++)
se#.add(i);
// Throws Concurren#Modifica#ionExcep#ion
for(In#eger elemen# : se#)
if(elemen# % 2 == 0)
se#.remove(elemen#);
Вот решение, но я не думаю, что оно очень элегантное:
Se#&l#;In#eger&g#; se# = new HashSe#&l#;In#eger&g#;();
Collec#ion&l#;In#eger&g#; removeCandida#es = new LinkedLis#&l#;In#eger&g#;();
for(in# i = 0; i &l#; 10; i++)
se#.add(i);
for(In#eger elemen# : se#)
if(elemen# % 2 == 0)
removeCandida#es.add(elemen#);
se#.removeAll(removeCandida#es);
Спасибо!
что вы делаете, это фильтрация или выбор, я бы предложил использовать Apache Commons.CollectionUtils, Там есть несколько мощных инструментов, и это делает ваш код "круче".
Вот реализация, которая должна обеспечить то, что вам нужно:
Set<Integer> myIntegerSet = new HashSet<Integer>();
// Integers loaded here
CollectionUtils.filter( myIntegerSet, new Predicate() {
public boolean evaluate(Object input) {
return (((Integer) input) % 2 == 0);
}});
Если вы часто используете один и тот же тип предиката, вы можете извлечь его в статическую переменную для повторного использования ... назовите его как-то так:EVEN_NUMBER_PREDICATE
, Некоторые могут увидеть этот код и объявить его «трудным для чтения». но это выглядит чище, когда вы выдвигаете предикат в статику. Тогда легко увидеть, что мы делаемCollectionUtils.filter(...)
и это кажется более читабельным (для меня), чем множество циклов по всему творению.
который делает вещи проще и безопаснее. Из документов API:
default boolean removeIf(Predicate<? super E> filter)
Removes all of the elements of this collection that satisfy the given predicate.
Errors or runtime exceptions thrown during iteration or by the predicate
are relayed to the caller.
Интересная заметка:
The default implementation traverses all elements of the collection using its iterator().
Each matching element is removed using Iterator.remove().
Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()) {
Integer element = iterator.next();
if (element % 2 == 0) {
iterator.remove();
}
}
Вы будете часто видеть эту модель, используяfor
петля, а неwhile
цикл:
for (Iterator<Integer> i = set.iterator(); i.hasNext();) {
Integer element = i.next();
if (element % 2 == 0) {
i.remove();
}
}
Как указали люди, используяfor
цикл является предпочтительным, потому что он содержит переменную итератора (i
в данном случае) ограничивается меньшей областью применения.
ConcurrentModificationException
потому что запись удалена черезSet.remove() в отличие отIterator.remove(), Если запись удалена черезSet.remove() пока выполняется итерация, вы получите исключение ConcurrentModificationException. С другой стороны, удаление записей черезIterator.remove() в то время как итерация поддерживается в этом случае.
Новый цикл for хорош, но, к сожалению, он не работает в этом случае, потому что вы не можете использовать ссылку на итератор.
Если вам нужно удалить запись во время итерации, вам нужно использовать длинную форму, которая использует итератор напрямую.
for (Iterator<Integer> it = set.iterator(); it.hasNext();) {
Integer element = it.next();
if (element % 2 == 0) {
it.remove();
}
}