使用for语句和while语句将迭代器向前移动的区别

15

当我使用Object的迭代器时,我会使用while循环(正如Bruce Eckel的《Java编程思想》中所写):

Iterator it=...

while(it.hasNext()){
    //...
}

但有时我看到一些人使用了 for循环

Iterator it=...
for (Iterator it=...; it.hasNext();){
    //...
}

我不理解这个选择:

  • 当我有一个带有序列号(如数组)或具有特殊步骤规则(通常声明为简单增量counter++)的集合时,我使用for循环
  • 当循环在没有这些限制的情况下以逻辑条件退出时,我使用while循环

这是一种编码风格问题还是存在其他逻辑(例如性能)我不知道的原因?

感谢每一个反馈


在https://dev59.com/nHE85IYBdhLWcg3w02_z中有一个将`Iterator`转换为与for-each循环`Iterable`兼容的示例。 - Vadzim
5个回答

32

for循环的正确语法是:

for (Iterator it = ...; it.hasNext(); ){
    //...
}

你代码中的前面声明是多余的,在for循环头中的额外分号也是如此。

你使用这种语法还是while循环只是口味问题,两者完全相同。 for 循环的通用语法是:

for (<init stmt>; <loop cond>; <iterate stmt>) { <body>; }

等同于以下代码:

<init stmt>;
while (<loop cond>) { <body>; <iterate stmt>; }

编辑:实际上,上述两种形式并不完全等价,如果(如问题所述)变量是在init语句中声明的。在这种情况下,迭代器变量的作用域将有所不同。对于for循环,作用域仅限于循环本身,在while循环的情况下,作用域延伸到封闭块的末尾(毫不奇怪,因为声明在循环外部)。

此外,正如其他人指出的那样,在较新版本的Java中,有一种简写的for循环符号:

for (Iterator<Foo> it = myIterable.iterator(); it.hasNext(); ) {
    Foo foo = it.next();
    //...
}

可以写成:

for (Foo foo : myIterable) {
    //...
}
当使用这种形式时,你当然会失去对迭代器的直接引用,而这是必要的,例如如果你想在迭代时删除集合中的项。

如果你在代码中添加“for”循环并同时引用有限的范围,那么这就成为了完美的答案。 - Michael Rutherfurd

9

这只是一种风格问题,就像您一样,当使用带有索引的内容时,我更喜欢使用for循环。如果您正在使用Java 5,当然应该使用foreach循环遍历集合:

Collection<String> someCollection = someCollectionOfString();
for (String element : someCollection) {
....
}

1
使用这种迭代器的唯一缺点是,您无法调用Iterator.remove()方法,因为您没有对Iterator对象的引用。 - Bill Michell
1
没错,但你很快就会发现! - tddmonkey

9
在for循环中声明Iterator的目的是为了最小化变量的作用域,这是一个好习惯。
当你在循环外部声明Iterator时,引用仍然有效/存在于循环完成后。99.99%的情况下,一旦循环完成,您不需要继续使用Iterator,因此这种风格可能会导致像这样的错误:
//iterate over first collection
Iterator it1 = collection1.iterator();
while(it1.hasNext()) {
   //blah blah
}

//iterate over second collection
Iterator it2 = collection2.iterator();
while(it1.hasNext()) {
   //oops copy and paste error! it1 has no more elements at this point
}

4

这两种方法之间并没有太大的区别,除了第一种方法在循环结束后记得 it 的值。第二种方法可能会抛出错误,因为你在循环内重新声明了变量。

实际上还有第三种方法可以解决这个问题。而不是像下面这样写:

for (Iterator<SomeObject> it = foo.iterator(); it.hasNext();) {
  SomeObject so = foo.next();
}

你可以最常见地编写:

。该标签用于定义段落。
for (SomeObject so: foo) {...}

这两者等同于同一件事情...

2
人们可能会使用显式的(“旧风格”)for循环,只是因为它对他们来说更加简洁,也许他们还没有适应新的语法(我个人认为新的语法更加简洁)。
长的for循环结构的一个实际优点是你有一个迭代器的引用,所以可以调用除了next()之外的其他方法。特别地,hasNext()经常很有用 - 想象一下如果你想打印出一个由逗号分隔的字符串列表:
StringBuilder sb = new StringBuilder();
for (Iterator it=...; it.hasNext();){
   sb.append(it.next());
   if (it.hasNext())
      sb.append(", ");
}

如果您使用更冗长的for循环,只是为了区分“这是最后一个”的情况,那么这种情况只是为了区分。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接