Вызов удаления в цикле foreach в Java



Answers

Вы не хотите этого делать. Это может привести к неопределенному поведению в зависимости от коллекции. Вы хотите использовать Iterator напрямую. Хотя для каждой конструкции используется синтаксический сахар и на самом деле используется итератор, он скрывает его от вашего кода, поэтому вы не можете получить к нему доступ, чтобы вызвать Iterator.remove .

Поведение итератора не определено, если базовая коллекция модифицирована, пока итерация выполняется каким-либо образом, кроме как путем вызова этого метода.

Вместо этого напишите свой код:

List<String> names = ....
Iterator<String> it = names.iterator();
while (it.hasNext()) {

    String name = it.next();
    // Do something
    it.remove();
}

Обратите внимание, что код вызывает Iterator.remove , а не List.remove .

Приложение:

Даже если вы удаляете элемент, который еще не был повторен, вы все равно не хотите изменять коллекцию, а затем использовать Iterator . Он может модифицировать коллекцию таким образом, что это удивительно и влияет на будущие операции на Iterator .

Question

В Java разрешено ли вызывать удаление в коллекции при повторении через коллекцию с использованием цикла foreach? Например:

List<String> names = ....
for (String name : names) {
   // Do something
   names.remove(name).
}

В качестве дополнения, законно ли удалять элементы, которые еще не были повторены? Например,

//Assume that the names list as duplicate entries
List<String> names = ....
for (String name : names) {
    // Do something
    while (names.remove(name));
}



Да, вы можете использовать цикл for-each. Для этого вам нужно сохранить отдельный список, чтобы удерживать удаление элементов, а затем удалить этот список из списка имен с помощью метода removeAll()

List<String> names = ....

// introduce a separate list to hold removing items
List<String> toRemove= new ArrayList<String>();

for (String name : names) {
   // Do something: perform conditional checks
   toRemove.add(name);
}    
names.removeAll(toRemove);

// now names list holds expected values



Убедитесь, что это не запах кода. Можно ли отменить логику и быть «включенным», а не «эксклюзивным»?

List<String> names = ....
List<String> reducedNames = ....
for (String name : names) {
   // Do something
   if (conditionToIncludeMet)
       reducedNames.add(name);
}
return reducedNames;

Ситуация, которая привела меня к этой странице, включала старый код, который зацикливался на List с помощью indecies для удаления элементов из списка. Я хотел реорганизовать его для использования стиля foreach.

Он зациклился на весь список элементов, чтобы проверить, какие у пользователя были права доступа, и удалил те, у которых не было разрешения из списка.

List<Service> services = ...
for (int i=0; i<services.size(); i++) {
    if (!isServicePermitted(user, services.get(i)))
         services.remove(i);
}

Чтобы отменить это, а не использовать удаление:

List<Service> services = ...
List<Service> permittedServices = ...
for (Service service:services) {
    if (isServicePermitted(user, service))
         permittedServices.add(service);
}
return permittedServices;

Когда «удалить» будет предпочтительнее? Одним из соображений является наличие большого списка или дорогостоящего «добавления» в сочетании с несколькими удаленными по сравнению с размером списка. Возможно, было бы более эффективно делать только несколько удалений, а не добавлять много. Но в моем случае ситуация не заслуживала такой оптимизации.




Лучше использовать Итератор, если вы хотите удалить элемент из списка

потому что исходный код удаления

if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
             numMoved);
elementData[--size] = null;

поэтому, если вы удалите элемент из списка, список будет реструктурирован, индекс другого элемента будет изменен, это может привести к тому, что вы хотите выполнить.




for (String name : new ArrayList<String>(names)) {
    // Do something
    names.remove(nameToRemove);
}

Вы клонируете names списков и итерации через клон, пока вы удаляете из исходного списка. Немного чище, чем верхний ответ.




Related