[英]Is removing elements from an ArrayList or LinkedList while iterating through it with a for loop in Java bad? If so, why?
我正在向某人展示我的代碼,他們說這會導致未定義的行為。 作為一名 Java 程序員,這不是我理解的。 在下面的代碼塊中,我將遍歷scenes
,這是一個 ArrayList,並從中刪除元素。
for(int i = 0; i < scenes.size() - 1; i++)
{
if(!(Double.valueOf(scenes.get(i + 1)) - Double.valueOf(scenes.get(i)) > 10))
{
scenes.remove(i + 1);
i--;
}
}
這會編譯並且不會在運行時引發異常,但我仍然不確定它是否是編程禁忌,為什么它是編程禁忌,以及正確的方法是什么。 我聽說過使用Iterator.remove()
以及創建一個全新的List
。
在ArrayList
中,從列表中間刪除一個元素需要您將所有具有較高索引的元素向下移動一個。 如果您執行一次(或少量),這很好,但如果您重復執行,則效率低下。
您也不想為此使用Iterator
,因為Iterator.remove()
也遇到了同樣的問題。
更好的方法是通過列表 go ,將要保留的元素移動到新位置; 然后在最后刪除列表的尾部:
int dst = 0;
for (int src = 0; src < scenes.size(); ++dst) {
// You want to keep this element.
scenes.set(dst, scenes.get(src++));
// Now walk along the list until you find the element you want to keep.
while (src < scenes.size()
&& Double.parseDouble(scenes.get(src)) - Double.parseDouble(scenes.get(dst)) <= 10) {
// Increment the src pointer, so you won't keep the element.
++src;
}
}
// Remove the tail of the list in one go.
scenes.subList(dst, scenes.size()).clear();
(這種“移位和清除”方法是ArrayList.removeIf
使用的方法;您不能在此處直接使用它,因為您無法檢查列表中的相鄰元素,您只能訪問當前元素)。
您可以采用類似的方法,該方法也可以有效地處理諸如LinkedList
之類的非隨機訪問列表。 您需要避免重復調用get
和set
,因為在LinkedList
的情況下這些是O(size)
。
在這種情況下,您將使用ListIterator
而不是普通索引:
ListIterator<String> dst = scenes.listIterator();
for (ListIterator<String> src = scenes.listIterator(); src.hasNext();) {
dst.next();
String curr = src.next();
dst.set(curr);
while (src.hasNext()
&& Double.parseDouble(src.next()) - Double.parseDouble(curr) <= 10) {}
}
scenes.subList(dst.nextIndex(), scenes.size()).clear();
或者類似的東西。 我沒有測試過它,而且ListIterator
使用起來總是很混亂。
這很簡單,適用於 ArrayList 或 LinkedList:
Iterator<String> iterator = list.iterator();
double current = 0;
double next;
boolean firstTime = true;
while (iterator.hasNext()) {
if (firstTime) {
current = Double.parseDouble(iterator.next());
firstTime = false;
} else {
next = Double.parseDouble(iterator.next());
if (next - current > 10) {
current = next;
} else {
iterator.remove();
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.