Skip to content

The remove bug

Java for AP CS A Lesson 11 1:54 English narration · English + 中文 subtitles burned in

space play · ←/→ 5s · j/l 10s · f fullscreen · ,/. speed

Chapters

Transcript
The safe way to keep only some items is not to remove the others — it is to build a second list. 要只留下一部分元素,安全的做法不是把其余的删掉—— 而是另建一个列表。
Walk the original, test each value, and the loop copies the matches across. 走一遍原来的列表,对每个值做判断, 循环就把符合的那些抄过去。
The original is untouched, which is exactly why filtering is safe and removing is not. 原来的列表毫发无损, 而这正是"筛选"安全、"删除"不安全的原因。
Now the most-tested trap in the whole course, and the code looks completely correct. 现在说整门课里最常考的那个陷阱,而这段代码看上去完全没问题。
The list is x, x, a, b. 列表是 x、x、a、b。
At i equals zero it finds an x and removes it — and everything slides down to close the gap, so the second x is now at index zero. i 等于 0 时它找到一个 x,把它删掉—— 于是后面的东西全都往前挪来补上缺口, 第二个 x 现在跑到了索引 0。
Then i moves on to one. 然后 i 走到了 1。
The second x was never looked at. 第二个 x 从头到尾没被看过一眼。
The loop finishes, an x is still in the list, and nothing crashed. 循环结束了,列表里还留着一个 x,而且什么都没报错。
The fix is one line. 修法只有一行。
Start at the end and count down. 从末尾开始,往回数。
Now when something is removed, everything that shifts is behind i — and i is heading the other way, so it never revisits that ground. 现在当某个元素被删掉时, 发生移位的都在 i 的"后面"—— 而 i 正朝着相反的方向走,它再也不会回到那片地方。
Same list, same removals, and nothing is ever skipped. 同样的列表,同样的删除, 而这一次什么都不会被跳过。
And there is a third version students try: removing inside an enhanced for. 还有第三种学生会试的写法:在增强 for 里面删除。
That one throws a ConcurrentModificationException — it crashes. 那一种会抛出 ConcurrentModificationException——它直接崩掉。
Oddly, that is the kind option. 说来奇怪,这反倒是"仁慈"的那一种。
The forwards indexed loop gives you a wrong answer silently, which is worse. 而正向带索引的循环会悄无声息地给你一个错答案, 那更糟。
Four things to take with you. 带走四点。
One: filtering into a new list is always safe. 第一:筛选到一个新列表永远是安全的。
Two: removing while looping forwards skips items. 第二:正向遍历时边删边走会漏掉元素。
Three: loop backwards when you must remove in place. 第三:非要就地删除,就倒着循环。
Four: never remove inside an enhanced for loop. 第四:绝不要在增强 for 循环里删除。
Now fix the loop in the task below. 现在去下面的题里把那个循环改好。

Log in or create account

IGCSE, A-Level & AP