【问题标题】:Unconventional use of Iterator to iterate over a collection非常规地使用 Iterator 来迭代集合
【发布时间】:2015-10-16 01:22:54
【问题描述】:

我知道List<String> list 的常规迭代器创建用法如下:

//Conventional-style
Iterator<String> iterator = list.iterator()
while(iterator.hasNext()){
   String string = iterator.next();
   //...further code goes here
}

但是,在Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop 接受的答案中,我遇到了for 循环使用这种不寻常的Iterator

//Unconventional for loop style
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
    String string = iterator.next();
    //...further code goes here
}

现在,我想知道:

  1. 这种非传统风格是否会一遍又一遍地为每次迭代在集合上创建迭代器?或者它是某种特殊的智能 for 循环,它创建一次迭代器并重用它? 如果它每次都创建一个迭代器,那不应该是性能问题吗?
  2. 我们能否将常规样式中的 while 循环行替换为 for(;iterator.hasNext();),如果我只使用 for 循环?

PS:我很清楚在集合上使用增强的 for 循环。我正在查看此内容的目的是“安全”删除元素,而不会导致ConcurrentModificationException

【问题讨论】:

  • 这是一个非常传统的迭代器使用;它只创建一次迭代器(for 循环的第一条语句,如果有的话,只执行一次)。事实上它完全等同于你的第一段代码
  • 不完全等价,这样iterator变量就不能再在for循环之外使用了,非常方便。
  • 你的第一个问题很奇怪(至少对我来说)。如果你看到这个for (int i = 0; i &lt; 10; i++) 会问同样的问题吗?您是否还会问是否在每次迭代时重新创建i? (是的,这与for 循环完全相同)
  • @Tom:是的.. 现在我意识到这一点似乎很愚蠢。感谢您用如此简单直接的示例指出这一点。我显然错过了。

标签: java performance for-loop while-loop iterator


【解决方案1】:

您称之为“非常规”的成语实际上是推荐的,因为它将迭代器变量的范围限制在使用它的循环中。

  1. 迭代器在循环开始之前创建一次。这遵循for 循环的一般语义,我强烈建议您熟悉它。

  2. 可以,但不建议这样做。这样的成语将是对while 成语的毫无意义的混淆。

最后,请注意,对于 99% 的用例,以上所有内容都没有实际意义,因为您确实应该使用 enhanced for 循环或 Java 8 forEach

【讨论】:

  • 非常感谢 Marko。“限制范围”部分对我来说是新的学习。我显然错过了 for 循环的“一般语义”。感谢您对我的愚蠢问题做出如此热情的回答。
  • 但是 ´for(Iterator i = c.iterator(); i.hasNext(); ) { doSomething(i.next()); }´ 是在引入 Iterable 之前迭代集合的最佳方式。如果你想使用 i.remove() 操作,仍然是这样。
  • @jan Iterable 本身与它无关(但我猜你的意思是它与 enhanced for 循环的连接)。是的,在 Java 5 之前,这是我们最好的习惯用法,是的,有 1% 的情况下您需要调用除 hasNext()next() 之外的任何其他内容。
  • 好的,因为作为第二个问题的答案,您告诉 OP 这是对 while 成语的毫无意义的混淆。
  • @jan 没错,绝对是。不过,也许你误解了我的陈述属于哪个成语。
【解决方案2】:

Java 源自 C,因此 for (A; B; C) { P; }A; while (B) { P; C; } 具有相同的语义。唯一的区别是变量的范围。特别是,A 部分只执行一次。因此,您的两个代码示例完全相同,但在 for-variant 中,变量的范围受到限制。

更现代的遍历集合的方式是增强 for 循环:

for (String string : list) {
    ...
}

但是,如果您想在迭代时删除或更改项目,您仍然需要迭代器版本。例如:

for (Iterator<String> it = list.iterator(); it.hasNext();) {
    String string = it.next();
    if (someFunction(string)) {
        it.delete();
    }
}

没有增强的 for 循环等效项。

【讨论】:

    【解决方案3】:

    1. 不,它不会一遍又一遍地创建迭代器。这是在 Java 包含接口 Iterable&lt;T&gt; 之前的完美风格。 如果您想在迭代集合时删除一个项目,则必须使用 iterator.remove() 方法(如果提供了该方法)。因为否则会引发 ConcurrentModificationException。

    如果您不想在迭代集合时删除项目,那么您应该只使用 for each 概念,该概念由实现 Iterable&lt;T&gt; 接口的每个集合提供。 (链接在最后以获取更多信息)

    for (String s : yourList) {
      ... // do something with the string
    }
    

    2. 是的!!使用 for 循环习惯用法。但正如我所说,如果您想使用 iterator.remove() 操作,而只是想遍历集合,则应该使用为每个概念提供的。

    您可以在此处找到很多关于 iterator.next() 方法的缺点以及为什么新集成的 for:each 概念更好的信息: https://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-26
      • 2018-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多