這是一個有效的方式找到並使用每個循環在Java中從一個LinkedList刪除項目,是有可能,不一致可能出現:鏈表:刪除對象
for(ObjectType ob : obList) {
if(ob.getId() == id) {
obList.remove(ob);
break;
}
}
這是一個有效的方式找到並使用每個循環在Java中從一個LinkedList刪除項目,是有可能,不一致可能出現:鏈表:刪除對象
for(ObjectType ob : obList) {
if(ob.getId() == id) {
obList.remove(ob);
break;
}
}
其他人所說的正確的觀點,通常這不是你如何remove
從對象採集。但是,在這種情況下,一旦你remove
一旦出現break
就沒有問題。
但是,如果您想在remove
之後繼續迭代,則需要使用迭代器。否則,你會得到一個ConcurrentModificationException
,或者在更一般的情況下,未定義的行爲。
所以,是的,如果你remove
break
出foreach
後,你會沒事的。
對於那些誰在說,這將失敗,因爲你不能在foreach
修改的集合 - 這是真實的,只有當你想保留迭代。這不是這種情況,所以這個捷徑很好。
A ConcurrentModificationException
被迭代器檢查並拋出。在這裏,remove
(其中有資格作爲併發修改)後,你break
出循環。迭代器甚至沒有機會檢測到它。
,如果你在break
添加評論,爲什麼它是絕對必要的,等等,因爲如果這個代碼後來被修改以繼續remove
迭代後,它會失敗這可能是最好的。
我會像對待這個成語類似goto
(或者更確切地說,標記break
/continue
):它可能在最初看起來錯的,但是用在刀刃上的時候,它使一個更乾淨的代碼。
編輯:的確,它會不要因爲休息而失敗。細節見polygenelubricant的答案。
但是,這是很危險的做法。爲了在Java中同時迭代和修改集合,必須使用「ListIterator」對象,並使用迭代器自己的「add()」和「remove()」方法,而不要使用集合中的那些方法。
您可以檢查Java文檔的「java.util.Iterator中」和「java.util.ListIterator中的」類
「Iterator」沒有「add()」方法。只有ListIterator有。你應該指出。 – whiskeysierra 2010-02-26 17:56:43
@Zorglub,注意'break'。這段代碼不會失敗。 – polygenelubricants 2010-02-26 18:03:19
它可能不會「失敗」,但代碼在任何正常意義上都是錯誤的。 – 2010-02-26 18:05:13
嘗試這樣:
Iterator<ObjectType> iter = obList.iterator();
while (iter.hasNext()) {
ObjectType ob = iter.next();
if(ob.getId() == id) {
iter.remove();
break;
}
}
這就是一個迭代器不能用foreach循環替換的最後的地方之一。
如果您在「移除」後出現「中斷」,則無需將其設置爲冗長。 – polygenelubricants 2010-02-26 17:54:35
@polygenelubricants:哦,你說得對。我沒有意識到異常只會發生在下一個循環中。 – Stroboskop 2010-02-26 17:59:15
如果這是一個鏈表,那麼Iterator.remove()比List.remove(Object)更有效,因爲後者必須重新搜索對象。我會使用迭代器,原則上它會被刪除。 – 2010-02-26 18:52:24
A 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);
}
}
你應該使用iterator.remove()
:
從底層集合 由 迭代器(可選操作)返回的最後一個元素刪除。這個 方法只能調用一次,每 調用一次。一個 迭代器的行爲是不確定如果的 底層的集合被修改 在迭代過程中在 不是通過調用此方法 以外的任何方式。
「迭代正在進行中」 - 這是這裏的重要區別。在他的情況下,一旦他修改了這個集合,他就放棄了這個迭代。這就是爲什麼我們要進行這個討論。但對於一般情況,你絕對正確。 – polygenelubricants 2010-02-26 18:22:07
爲了避免ConcurrentModifiationException
,你可以這樣做:
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一起使用,而第二個建議需要List。
只需在for循環中使用迭代器即可。 – 2010-02-26 18:15:45
這會使循環的最後部分爲空。我不喜歡那樣。一陣子完全適合那裏。 – whiskeysierra 2010-02-26 18:32:55
此代碼可能會執行多次刪除。這是與原始代碼不同的行爲,最多刪除一個元素。 – polygenelubricants 2010-02-26 18:42:24
最好使用迭代器,並通過遍歷集合來搜索對象以移除它時使用它的remove方法。這是因爲
我建議,原則上,前述的增強並使用這樣的事情,而不是:
for(Iterator<ObjectType> it=obList.iterator(); it.hasNext();) {
if(it.next().getId()==id) {
it.remove();
break;
}
}
這樣,你不做出關於可能在將來改變基礎列表假設。
比較的代碼,以消除迭代器刪除所謂的最後一個條目(格式化太陽):
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;
}
反對什麼刪除(對象)必須做到:
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;
}
你沒有回答我所問的內容,但這很好。 – Xolve 2010-02-27 15:17:23
以上第二個循環應該改變一下
for (int i = 0; i < obList.size();) {
if (obList.get(i).getId() == id) {
obList.remove(i);
continue
}
++i;
}
或
for (int i = obList.size() - 1; i >= 0; --i) {
if (obList.get(i).getId() == id) {
obList.remove(i);
}
}
我還沒有檢查過語言規範,但不是foreach語法,只是在後臺使用迭代器的編譯器魔法? – Powerlord 2010-02-26 17:56:37
是的,它確實在場景後面使用迭代器,並且該迭代器對您是隱藏的。 – polygenelubricants 2010-02-26 17:58:27
但是,當nexte開發人員嘗試添加一些功能而不「看到」該陷阱時,它很可能在未來的版本中失敗。那麼你應該記錄清楚。 – whiskeysierra 2010-02-26 17:58:57