【问题标题】:Do we ever need to use Iterators on ArrayList?我们是否需要在 ArrayList 上使用迭代器?
【发布时间】:2013-03-27 12:01:33
【问题描述】:

昨天,当我回答问题getting ConcurrentModificationException error while using iterator and remove时,我添加了一条通知

当你有 ArrayLists 时使用迭代器不是一个好主意。

您无需深入理解该问题即可回答该问题。

那里,我有两个错误。

我的论点:

  1. 使用迭代器时代码的可读性要差得多。

  2. 有可能引发难以调试的 ConcurrentModificationException。

你能解释一下吗?

问题: 我们是否需要在 ArrayList 上使用迭代器?

UPD

这是关于显式使用迭代器。

【问题讨论】:

  • 取决于“使用迭代器”的含义。每次您执行for (Integer x: listOfInts) 时,您都在隐式使用迭代器。
  • @Oli Charlesworth,感谢您指出这一点!是的,我的意思是显式迭代器。

标签: java


【解决方案1】:

使用 ArrayLists 的迭代器的一个重要用例是当您想要在迭代时删除元素。您只有三个安全的解决方案:

  • 使用迭代器及其remove 方法
  • 复制要保留在另一个列表中的元素
  • 带索引的丛林

假设您在迭代时不add,使用迭代器是一种避免ConcurrentModificationException的手段。

可读性参数是主观的。就我个人而言,我没有发现一个明确声明的迭代器可读性较差。这并不重要,因为迭代器是同时进行迭代和删除的安全方式。

【讨论】:

  • 对我来说唯一好看的理由是:“使用迭代器及其删除方法”。如果有人只想迭代并从列表中删除不需要的项目。谢谢。
  • @dystroy 很抱歉打开它,但我不明白您为什么需要使用迭代器从 ArrayList 中删除元素?
  • @Vitaly 我做了一个快速测试 List a = new ArrayList(); a.add("a"); a.add("b"); a.add("c"); a.add("d"); a.add("e"); a.remove("b");它似乎有效。
  • @12rad 如果您直接或使用迭代器循环遍历数组列表,同时从数组列表中删除元素,如果不这样做,您将遇到问题(错误或 ConcurrentModificationException) '不使用迭代器的特定remove方法。
  • @dystroy 我明白了,所以,只有当我真正循环播放时。但是如果我只是添加元素,然后通过 a.remove("b) 删除一个,它是安全的吗?-------- Like:List a = new ArrayList(); a.add( "a"); a.add("b"); a.add("c"); a.add("d"); a.add("e"); a.remove("b");
【解决方案2】:

是的,我们需要。 ArrayList 只是 List 接口的一个实现,因此您的代码通常会处理一个列表,甚至不知道它是一个 ArrayList。此外,新的 for 循环语法在内部使用迭代器。

【讨论】:

  • 谢谢。这是关于 ArrayList 的。
【解决方案3】:

您可能在谈论显式使用迭代器(因为 : 运算符也在幕后使用迭代器)。

假设您想让两个“指针”遍历数组,但速度取决于实际元素值。 如果不显式使用迭代器(当然也没有 elementAt),你将如何做到这一点。

例如(伪代码):

element1 = first element;
element2 = first element;
while(element1.hasNext && element2.hasNext)
{
    if(element1 * 2 < element)
    {
        element2 = element2.next;
    }
    else
    {
        element1 = element1.next;
    }

    //do something with the pair of elements
}

【讨论】:

  • 谢谢。我们可以使用 ArrayList.elementAt(),为什么不呢? :) 你能澄清一下“速度取决于实际元素值”是什么意思吗?
  • @Vitaly 因为那你的代码是 ArrayList 特定的,而不是通用的任何 List.
  • 这不是“我的代码”:) 问题是关于我们是否知道它是 ArrayList。
【解决方案4】:

使用迭代器时代码的可读性要差得多。

这完全是你的意见,我不同意。

有可能引发难以调试的 ConcurrentModificationException。

无论您是否使用迭代器,这都可能存在。该异常会告诉你一些有用的代码,否则你可能会完全错过,这更难调试。

我个人更喜欢能够在 ArrayList 和 LinkedList 之间准确编写代码,并让编译器或 API 实现细节。

道德是你不应该把你自己不受支持的观点当作既定事实。

【讨论】:

    【解决方案5】:

    查看这篇文章: http://www.xyzws.com/javafaq/what-is-the-advantage-of-using-an-iterator-compared-to-the-getindex-method/19

    使用迭代器可以避免在LinkedList上使用get(index)的错误(非常慢)。当 list 的实现未知时才有意义,只需使用 iterator。关于 ArrayList,使用迭代器仍然会通过 get(index) 实现最接近的性能。

    因此,从性能角度来说,使用迭代器进行迭代是一种很好的做法。

    【讨论】:

      【解决方案6】:

      似乎没有一个答案能说明迭代器的原因。创建迭代器设计模式是因为对象应该控制自己的状态(除了可能只有公共属性的值对象)。

      假设我们有一个包含数组的对象,并且您在该对象中有一个接口可以将项目添加到该数组中。但是你已经做了这样的事情:

      class MyClass
      {
          private ArrayList<Item> myList;
      
          public MyClass()
          {
              myList = new ArrayList();
          }
      
          public addItem( Item item )
          {
               item.doSomething(); // Lets say that this is very important before adding the item to the array.
               myList.add( item );
          }
      }
      

      现在如果我在上面的类中有这个方法:

      public ArrayList getList()
      {
          return myList;
      }
      

      有人可以通过这个方法获得对 myList 的引用并将项目添加到数组中,无需调用 item.doSomething();这就是为什么你不应该返回对数组的引用,而是返回它的迭代器。可以从数组中获取任何项目,但不能操作原始数组。所以 MyClass 对象仍然控制着它自己的状态。

      这就是发明迭代器的真正原因。

      【讨论】:

      • 我知道这是旧的,但我还是要对此发表评论。您的声明 you shouldn't return a reference to the array, but instead return its iterator. One can get any item from the array, but it can't manipulate the original array. 适用于常规的旧 Iterator,但是 ListIterator 可以在原始列表中添加更多元素。
      猜你喜欢
      • 2013-04-06
      • 2016-08-01
      • 2017-08-10
      • 2010-11-16
      • 2020-01-16
      • 2010-12-22
      • 1970-01-01
      • 2022-11-14
      • 1970-01-01
      相关资源
      最近更新 更多