【问题标题】:Why do we need to use iterator on ArrayList in Java? [duplicate]为什么我们需要在 Java 中的 ArrayList 上使用迭代器? [复制]
【发布时间】:2013-04-06 16:30:46
【问题描述】:

我正在阅读问题中提到的答案 “Do we ever need to use Iterators on ArrayList?”。

在回答中,用户这样说:“使用 ArrayLists 的迭代器的一个重要用例是当您想要在迭代时删除元素”。

这甚至可以在 Java 中使用 ArrayList 的 remove 方法来实现。我的问题是为什么我们需要 ArrayList 中的迭代器?

考虑代码:

import java.util.*;
public class ocajp66 {
    public static void main(String[] args) {
        ArrayList a = new ArrayList();
        for (int i = 0; i < 10; i++) {
            a.add(i);
        }
        System.out.printf("BEFORE ITERATOR\n");
        for (int i = 0; i < a.size(); i++) {
            System.out.printf("I:%d\n", a.get(i));
        }
        System.out.printf("AFTER ITERATOR\n");
        Iterator i = a.iterator();
        while (i.hasNext()) {
            System.out.printf("I:%d\n", i.next());
        }
    }
}

谁能解释一下迭代器的意义?如果你能用代码解释我,那就太好了。

【问题讨论】:

  • "在java中使用ArrayList的remove方法也可以实现。"你试过这个吗?
  • 这个问题与链接的问题有何不同?
  • @Nambari 作为java初学者我想知道java中迭代器的意义为什么我们需要它当可以使用循环修改/删除/插入时
  • @Howard 在链接的问题中我无法理解迭代器的重要性。

标签: java arraylist iterator


【解决方案1】:

正如您所说,当您在迭代数组内容时想要删除内容时使用迭代器。如果您不使用迭代器,而只是有一个 for 循环并在其中使用 remove 方法,您将得到异常,因为在您迭代时数组的内容会发生变化。例如:你可能认为在 for 循环开始时数组大小是 10,但一旦你删除东西就不会这样了。所以当你到达最后一个循环时,可能会有 IndexOutofBoundsException 等。

【讨论】:

  • 这不是正确的答案。迭代器是一种封装数组的方法,因此您无法编辑它们的内容。您所说的内容后来被添加到迭代器中。
  • 这就是为什么你使用 array.size() 作为 for 循环条件而不是幻数。
【解决方案2】:

很明显,ArrayList-like API 可以在没有iterator() 方法的情况下工作。但是,ArrayListCollectioniterator() 方法是在 Collection 接口中定义的......所以 ArrayList 来实现它。

关于从ArrayList 中删除的要点是,通过索引来执行此操作需要一些思考:

    for (int i = 0; 
         i < a.size(); // Hoist this at your peril
         i++) {
        if (a.get(i) == something) {
            a.remove(i);
            i--;  // Leave this out at your peril
        }
    }

如果你需要从循环调用的方法中删除列表元素,情况会变得更糟......'因为该方法必须说它已经删除了一个元素,以便调用者可以调整循环索引。

iteratorArrayList 上是个好东西的第三个原因是它允许您使用 Java 5 的 for (type var : iterable) ... 语法。

底线是您不必必须ArrayList 实例上使用迭代器。如果你不想,那就不要。

【讨论】:

  • 您可以直接在 ArrayList 上使用 for 循环表示法;不需要迭代器。在遍历期间删除元素是唯一的原因。拥有一个带有删除标记的 ArrayList 会很酷,它以某种方式在循环结束时删除了所有标记的元素。一个人可以做梦:)
  • 除了修改迭代变量被认为是一种不好的做法,你永远不应该这样做。
  • @pseudo - 这是真的,但我不明白你为什么在这里提到它。我的回答或任何 cmets 建议人们应该修改循环变量吗??
  • @RobertGrant:你不能向后遍历数组吗?从 size-1 开始,在 0 结束。
  • @adam.r - 我认为你误解了罗伯特的评论。向后遍历数组(列表)并不能实现任何目标,当然也不能解决高效安全删除元素的问题。
【解决方案3】:

问:为什么我们需要 ArrayList 中的迭代器?

我们不这样做 - 正如您在代码中所示,您可以在没有迭代器的情况下对 ArrayList 进行迭代和执行核心操作。不过有功能还是不错的。

问:谁能解释一下迭代器的意义?

除了它的设计价值之外,我还可以看到它的快速故障功能。我从ArrayList documentation引用这段话:

这个类的迭代器和listIterator返回的迭代器 方法是fail-fast:如果列表在任何结构上被修改 迭代器创建后的时间,除了通过 迭代器自己的删除或添加方法,迭代器会抛出一个 并发修改异常。因此,面对并发 修改,迭代器快速而干净地失败,而不是 在不确定的时间冒着任意的、不确定的行为的风险 未来。

您正在寻找代码,您实际上可以在这里看到 ArrayList 的迭代器实现:ArrayList.java

【讨论】:

  • 你的答案有什么特别之处需要使用这种大字体吗?
  • 好了,把它变小了。
【解决方案4】:

这是一个示例,说明如何通过多种不同方式获得您想要的结果。这种冗余并不是 Java 独有的。

  • for (int i=0; i

这种语法是在 Java 的早期版本中引入的。它在 for { } 循环中迭代一个普通的 Java 数组。这通常是安全的,因为 Java 数组是固定长度的,因此不可能出现“索引越界”异常。

  • for (int i=0; i

此语法反映了 Java 的较晚版本,在引入了引入 ArrayList 的 Collections API 之后。如上所述,实现 Collection 接口的类必须实现 Iterator,但您不必使用它。这个 for { } 循环没有,但这里的危险是 ArrayLists 不是固定大小的。如果它应该在你的 for 循环体中收缩,就会导致异常。

  • for (MyArrayType t : myArrayList) { }

此语法也在 Java 的更高版本中发布。它被称为增强的 for 循环。任何通过实现 Iterable 接口来提供 Iterator 的集合类都可以利用此语法。这允许迭代集合中的项目,而无需显式实例化迭代器。在 JavaFX 应用程序中使用它的一种最喜欢的方法是循环通过一堆控件来将属性设置为一个值,例如。重置一组 TextField 的内容:

for (TextField tf : new TextField[] { txtf1, txtf2, txtf3, txtfa, txtfb, txtfc}) {
    tf.setText("");
}
  • while (myCollectionIterator.hasNext()) { }

你总是可以显式地实例化一个迭代器。当集合大小发生变化时(来自集合自己的方法),这可以安全使用。说 Iterator 更接近于 Iterable 接口的属性而不是核心 Java 语言的特性是正确的。但是您仍然可以将其用作类似语言的功能(在增强的 for 循环中),这要归功于更高版本的 Java 版本。

这些结构提供了冗余,但它们并不相同。每一个都有细微差别,使一个在给定时间特别有用。您应该使用所有这些。

【讨论】:

  • 感谢您提供有用的信息
【解决方案5】:

对于您的问题,如果我们使用list.remove() 方法而不是iterator.remove(),那么IndexOutOfBoundsException 将被抛出。

list.remove() 使用 break 声明时是安全的

如果我们在同步环境中使用迭代器,以下迭代器代码仍然可以抛出ConcurrentModificationException

List<String> empNames = new ArrayList<String>();
        synchronized (empNames) {
            Iterator<String> iterator = empNames.iterator();
            while (iterator.hasNext()) {
                iterator.next();
                empNames.add("Another Name"); // throws
                // ConcurrentModificationException
            }
        }

【讨论】:

  • 如果我们使用 list.remove() 为什么我们会得到错误 IndexOutOfBoundsException ?
猜你喜欢
  • 2013-03-27
  • 2010-11-16
  • 2010-09-15
  • 2016-08-01
  • 1970-01-01
  • 2015-08-27
  • 1970-01-01
  • 1970-01-01
  • 2018-02-23
相关资源
最近更新 更多