为什么我们要尽可能使用Iterator接口中的remove方法而不是用Collection接口中的remove方法

最近在看《数据结构与算法分析》(Java语言描述)一书,看到第3.3.2 这一节时介绍Iterator接口。书中说道,“Iterator接口中包含一个方法,叫做remove()。该方法可以删除next最新返回的项。虽然Collection接口也包含一个remove方法,但是,使用Iterator的remove可能有更多的优点。”
那么首先我们知道Collection接口是继承于Iterator接口,如下图所示:
为什么我们要尽可能使用Iterator接口中的remove方法而不是用Collection接口中的remove方法_第1张图片
那么Collection接口中的remove()比Iterator接口中的remove()的差异性到底在哪呢?我们可以先从他们的API中看出方法的不一样。如下图所示:
第一张是Iterator接口中的remove(),第二张是Collection接口中的remove()。
为什么我们要尽可能使用Iterator接口中的remove方法而不是用Collection接口中的remove方法_第2张图片
为什么我们要尽可能使用Iterator接口中的remove方法而不是用Collection接口中的remove方法_第3张图片
那么从方法体上看有着明显的不同了,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接口中只提供了三个方法:
为什么我们要尽可能使用Iterator接口中的remove方法而不是用Collection接口中的remove方法_第4张图片
只有remove方法是能改变集合结构的,并没有提供其它改变集合结构的方法。所以,在集合遍历时,你使用Collection接口提供的方法改变集合结构,就会报异常的。你使用Iterator接口中的remove方法就不会报异常,具体是为什么呢?在这里大家可以看这个这位朋友的博客
Iterator的remove()和Collection的remove()

你可能感兴趣的:(Java基础)