为什么扩展for循环不适用于迭代器?

时间:2011-12-18 21:22:59

标签: java for-loop

  

可能重复:
  Why is Java's Iterator not an Iterable?

我们都知道java的扩展for循环:

List<X> list = ...
for(X x : list) { ... }

我需要的是:

Iterator<X> listIterator = ...
for(X x : listIterator){ ... }

Java不允许这样做。 我想知道规范是否支持此是否有充分理由。

这是我的用例:

我正在为一种文件格式编写阅读器。这样的文件包含要读取的条目。为了这个例子,假设我正在尝试重新发明BufferedReader,我的元素是字符串。

我对原始BufferedReader的API样式非常不满,这迫使我编写丑陋的代码,如:

for(String line = reader.readLine(); line != null; line = reader.readLine(){
   ...
}

我宁愿拥有像

这样的好东西
for(String line : reader){
   ...
}

当然,我可以制作BufferedReader工具Iterable<String>。但这意味着可能会多次调用iterator()方法。由于我无法在文件中查找,因此我无法真正支持多个并行迭代器。

让我的BufferedReader工具Iterator<String>代替Iterable<String>似乎更合理。但后来我不能使用for语句: - (

2 个答案:

答案 0 :(得分:1)

当然,您可以支持多个并行迭代器。您可以多次打开该文件。

class BufferedReader() implements Iterable<String> {
    String fileName;
    InputStreamReader in;

    public BufferedReader(String fileName) {
      this.fileName = fileName;
      in = new InputStreamReader(new FileInputStream(fileName));
    }
    public Iterator<String> iterator() {
        return new Iterator<String>() {
            BufferedReader in = new BufferedReader(fileName);
            String nextLine = in.readLine();
            public boolean hasNext() {
                return nextLine != null;
            }
            public String next() {
              String str = nextLine;
              nextLine = in.readLine();
              return str;
            }
        }
    }
}

答案 1 :(得分:1)

因为foreach循环的合同是迭代每个元素。如果只允许Iterator,你就可以给它消耗一半Iterator而且它不会知道差异。

Set<String> set = new HashSet(Arrays.asList(new String [] {"One", "Two", "Three"}));
Iterator i = set.iterator();
// Consume the first.
String first = i.next();
for ( String s : i ) { // Error here.

}

我接受它会让事情变得更容易,但它也会引入一些严重的错误,因为你不知道你已经涵盖了集合中的所有条目。

// Works fine because Set is Iterable and the contract is satisfied 
// that this will iterate over <b>all</b> of the entries.
for ( String s : set ) {
}

你可以通过短暂的Iterable来破解它。我现在无法测试这个,但是像:

for ( String s : new Iterable { 
  public iterator<String> () {
    return set.iterator ();
  }
} ) {
}

虽然很麻烦,但应该可以。