1. 程式人生 > >為什麼我們要儘可能使用Iterator介面中的remove方法而不是用Collection介面中的remove方法

為什麼我們要儘可能使用Iterator介面中的remove方法而不是用Collection介面中的remove方法

最近在看《資料結構與演算法分析》(Java語言描述)一書,看到第3.3.2 這一節時介紹Iterator介面。書中說道,“Iterator介面中包含一個方法,叫做remove()。該方法可以刪除next最新返回的項。雖然Collection介面也包含一個remove方法,但是,使用Iterator的remove可能有更多的優點。”
那麼首先我們知道Collection介面是繼承於Iterator介面,如下圖所示:
這裡寫圖片描述
那麼Collection介面中的remove()比Iterator介面中的remove()的差異性到底在哪呢?我們可以先從他們的API中看出方法的不一樣。如下圖所示:
第一張是Iterator介面中的remove(),第二張是Collection介面中的remove()。
這裡寫圖片描述


這裡寫圖片描述
那麼從方法體上看有著明顯的不同了,Collection介面中的remove方法必須接受一個物件,即要從集合中移除的對像,並且返回boolean值。而Iterator介面中的remove方法,它通過迭代器,每次使用next後,讓指標往後移一位後,再使用remove方法移除當前指標指向的物件(這個Iterator介面中的next方法和remove方法之間的關係,大家感興趣可以查一下資料或者自行看一下java原始碼),然後他的方法是void的,沒有返回值的。
那好,使用Iterator的remove方法優點之一就是:

  • Collection的remove方法必須首先找出要被刪除的項。因此如果知道所要刪除的項的準確位置,那麼刪除它的開銷很可能要小得多。(如果不知道呢,那麼首先得找到這個物件的位置,瞭解單鏈表結構的同學都知道,單鏈表的查詢效率比較低,它得從表頭一個個遍歷了比較才能找到這個物件)但是下一節我們將要看到一個例子,是在集合中每隔一項刪除一項。這個程式用迭代器很容易編寫,而且比用Collection的remove方法潛藏著更高的效率。

  • 然後書中接著介紹到:“當直接使用Iterator(而不是通過一個增強的for迴圈間接使用)時,重要的是要記住一個法則:如果對正在被迭代的集合進行結構上的改變(即對該集合使用add、remove或clear方法),那麼迭代器就不再合法(並且在其後使用該迭代器時將會有ConcurrentModificationException異常丟擲)。為了避免呆呆起準備給出某一項作為下一項(nextitem)而該項此後或者被刪除,或者也許一個新的項正好插入該項的前面這樣一些討厭的情形,有必要記住上述法則。這樣意味著,只有在需要在立即使用一個迭代器的時候,我們才應該獲取迭代器。然後,如果迭代器用了他自己的remove方法,那麼這個迭代器就仍然合法的。這是有時候更願意使用迭代器的remove方法的第二個原因。”

好,當我讀完上一段時候,我得到了2個資訊。

  1. 當我們在遍歷集合時,如果這當中出現改變集合結構的操作(add、remove或clear方法),會丟擲ConcurrentModificationException異常。
  2. 但是,當我們獲取這個集合的迭代器然後用迭代器進行遍歷時,出現改變集合結構的操作,不會丟擲異常。

後來發現我第二個資訊的理解是錯的,當我們獲取這個集合的迭代器然後用迭代器進行遍歷時,只有迭代器用了他自己的remove方法時,才不會報異常,如果你執行了其他可能改變集合結構的操作它還是會拋異常。因為只有Iterator介面的方法是安全的。而Iterator介面中只提供了三個方法:
這裡寫圖片描述
只有remove方法是能改變集合結構的,並沒有提供其它改變集合結構的方法。所以,在集合遍歷時,你使用Collection介面提供的方法改變集合結構,就會報異常的。你使用Iterator介面中的remove方法就不會報異常,具體是為什麼呢?在這裡大家可以看這個這位朋友的部落格
Iterator的remove()和Collection的remove()