Это, допустимый способ найти и удалить объект из LinkedList в Java с помощью для каждого цикла, является этим возможный, что несоответствие может возникнуть:
for(ObjectType ob : obList) {
if(ob.getId() == id) {
obList.remove(ob);
break;
}
}
Другие указывали на то, что обычно это не так, как вы удаляете
объект из коллекции. КАЧЕСТВЕННО, в данном случае это нормально, так как Вы вырываете
из цикла после того, как Вы удаляете
.
Если вы хотите продолжить итерацию после удаления remove
, то вам необходимо использовать итератор. В противном случае вы получите ConcurrentModificationException
, или, в более общем случае, неопределенное поведение.
Так что да, если вы вырвете
из foreach
после того, как вы удалите
, все будет в порядке .
Для тех, кто говорит, что это не удастся, потому что вы не можете изменить коллекцию в foreach
- это верно только в том случае, если вы хотите продолжить итерацию. Здесь дело не в этом, так что этот ярлык в порядке.
A ConcurrentModificationException
проверяется и выбрасывается итератором. Здесь, после удаления remove
(что квалифицируется как одновременная модификация), вы вырываете
из цикла. Итератор даже не успевает это обнаружить.
Возможно, будет лучше, если вы добавите комментарий к break
, почему он абсолютно необходим и т.д., потому что если этот код будет позже модифицирован для продолжения итерации после remove
, он потерпит неудачу.
Я бы относился к этой идиоме так же, как к goto
(или, скорее, как к break
/continue
): сначала она может показаться неправильной, но при разумном использовании она делает код чище.
Попробуйте что-то вроде этого :
Iterator<ObjectType> iter = obList.iterator();
while (iter.hasNext()) {
ObjectType ob = iter.next();
if(ob.getId() == id) {
iter.remove();
break;
}
}
Это одно из последних мест, где итератор не может быть заменен циклом foreach.
Другим вариантом может быть использование массива boost:: необязательный < Foo >
:
boost::optional<Foo> foos[10]; // No construction takes place
// (similar to vector::reserve)
foos[i] = Foo(3); // Actual construction
Одно из предостережений состоит в том, что доступ к элементам должен осуществляться с помощью синтаксиса указателя:
bar(*foos[2]); // "bar" is a function taking a "Foo"
std::cout << foos[3]->baz(); // "baz" is a member of "Foo"
Также необходимо быть осторожным, чтобы не получить доступ к неинициализированному элементу.
Другое предостережение заключается в том, что это не является истинной заменой массива Foo
, поскольку вы не сможете передать его функции, которая ожидает последнего.
В некоторых (большинстве?) систем трубы по умолчанию используют буферизацию ввода-вывода. Поместите инструкцию
$handle->autoflush(1);
в функцию myPipe
.
Но даже когда буферизация отключена, Perl по-прежнему не сбрасывается, кроме как после новой строки. Таким образом, может потребоваться, чтобы дочерний процесс включил в вывод новую строку.
Обновление: Тестирование кода (Cygwin, perl 5,10,0, YMMV), я вижу проблему в отсутствии новой строки в дочернем выводе, а не в том, включена ли автоматическая очистка при создании трубы.
-121--3832323- Чтобы избежать ConcurrentModifyException , можно сделать следующее:
final Iterator<ObjectType> i = obList.iterator();
while (i.hasNext()) {
if (i.next().getId() == id) {
i.remove();
}
}
или
for (int i = 0; i < obList.size(); i++) {
if (obList[i].getId() == id) {
obList.remove(i);
}
}
я бы предпочел первое. Обработка индексов более подвержена ошибкам, и итератор может быть реализован эффективно. И первое предложение работает с Iterable, в то время как второе требует списка.
Лучше всего использовать итератор и использовать его метод удаления при поиске объекта путем итерации сборник, чтобы удалить его. Это потому, что
В принципе, я рекомендую отказаться от расширенного и использовать вместо него что-то вроде этого:
for(Iterator<ObjectType> it=obList.iterator(); it.hasNext(); ) {
if(it.next().getId()==id) {
it.remove();
break;
}
}
Таким образом, вы не делаете предположений о базовом списке, который может измениться в будущем.
Сравните код для удаления последней записи, вызванной итератором remove (форматирование Sun):
private E remove(Entry<E> e) {
if (e == header)
throw new NoSuchElementException();
E result = e.element;
e.previous.next = e.next;
e.next.previous = e.previous;
e.next = e.previous = null;
e.element = null;
size--;
modCount++;
return result;
}
с тем, что должен сделать remove (Object):
public boolean remove(Object o) {
if (o==null) {
for (Entry<E> e = header.next; e != header; e = e.next) {
if (e.element==null) {
remove(e);
return true;
}
}
} else {
for (Entry<E> e = header.next; e != header; e = e.next) {
if (o.equals(e.element)) {
remove(e);
return true;
}
}
}
return false;
}
Вы должны использовать iterator.remove ()
:
Удаляет из базовой коллекции последний элемент, возвращенный итератором (необязательная операция). Этот метод может быть вызван только один раз за каждый вызов следующего. Поведение итератора не указано , если базовая коллекция изменяется во время выполнения итерации в любым другим способом, кроме вызывая этот метод .
Edit: Действительно, это не приведет к сбою благодаря прерыванию. Подробности см. в ответе polygenelubricant.
Однако, это опасный способ. Чтобы одновременно выполнять итерацию и изменять коллекцию в Java, вы должны использовать объект "ListIterator", и использовать собственные методы итератора "add()" и "remove()", а не методы коллекции.
Вы можете проверить java doc для классов "java.util.Iterator" и "java.util.ListIterator"
CopyOnWriteArrayList
может быть тем, что вы ищете. Когда выполняются мутирующие операции, создается копия базового массива. Это позволяет изменять элементы списка внутри цикла for-each. Однако помните, что это не связанный список, и он может быть весьма неэффективным.
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class Main {
public static void main(String[] args) {
List<String> myList = new CopyOnWriteArrayList<String>();
myList.add("a");
myList.add("b");
myList.add("c");
// Will print [a, b, c]
System.out.println(myList);
for (String element : myList) {
if (element.equals("a")) {
myList.remove(element);
}
}
// Will print [b, c]
System.out.println(myList);
}
}