拡張forループがイテレータで機能しないのはなぜですか?

Possible Duplicate:
Why is Java's Iterator not an Iterable?

我々は、javaの拡張された for ループを知っています:

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

私が必要とするものは次のとおりです。

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

Javaではこれを許可していません。 仕様がこれをサポートしていない理由があるのか​​どうかは疑問でした

ここに私のユースケースがあります:

私は一種のファイル形式のための読者を書いています。このようなファイルには、読み取られるエントリが含まれています。この例では、私はBufferedReaderを再開発しようとしていて、私の要素はStringsであると仮定します。

私は元の BufferedReader のAPIスタイルには不満があります。そのため、次のような醜いコードを書くよう強制します。

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

私はむしろ何かいいものを持っているだろう

for(String line : reader){
   ...
}

Of course I can make my BufferedReader implement Iterable. But this implies that there is a iterator() method that might be called several times. Since I cannot seek in the file, I cannot really support multiple parallel iterators.

Having my BufferedReader implement Iterator instead of Iterable seems far more reasonable. But then I can't use the for statement :-(

3
再び、私はそれが重複していることに同意します。私は2つのインターフェースの相違点をよく知っています。私はなぜこの違いがforループに関して関係があるのか​​を尋ねています。私はまた、このように指定されていることを認識しています。私はなぜそれがこのように指定されたのだろうと思っています。
追加された 著者 Stefan,
@ coding.mof仕様に従って一度だけ呼び出されます。
追加された 著者 Stefan,
見出しの質問に対する答えは、「それが言語が定義されている方法なので」です。
追加された 著者 Oliver Charlesworth,
拡張forループとiteratorを持つforループとの間には効果的な違いはありません。 (forループ)(X x:myList)の拡張forループは、(Iterator it = myList.iterator); it.hasNext();){ X x = it.next(); ...} あなたの場合、イテレータからイテレータを取得しようとします(これは意味をなさない)。しかし、あなたのユースケースをターゲットにする: String line = null; while((line = reader.readLine())!= null){...} あなたがラインの数を知らないなら、whileループはより論理的です
追加された 著者 thomas,
アドバンストループが「イテレータ」メソッドを複数回呼び出すかどうかを確認しましたか?私はそれが一度だけ行うと仮定します..
追加された 著者 Marc-Christian Schulze,

2 答え

foreach ループのコントラクトは every 要素を反復するためです。 Iterator を取ることだけが許されていれば、それは半分を消費する Iterator とすることができ、その違いを知ることはできません。

Set 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 all of the entries.
for ( String s : set ) {
}

一時的な反復可能を作成することで、いつでもハックすることができます。私はこれを今はテストできませんが、次のようなものです:

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

面倒ですが、うまくいくはずです。

1
追加された
静的メソッドを使用してハックをよりきれいに実装することができます。関連する質問に追加しました。
追加された 著者 McDowell,
良い点ポール。文法的にはエレガントですが、ファイルの途中で開始するとforeachのセマンティクスが変更されます。シーク不可能なストリームからの読み込みはforeachのセマンティクスに追いついていないため、回避してもそれを使用するのは間違いです。
追加された 著者 Stefan,
@McDowell - ありがと...私はマシン上で今はjava 5を持っていないので、私はそれをテストできませんでした。これは、一度しか使用できない Iterator をどのように作成したのかが賢明です。 @Lawnmower - 特に Iterator this に戻して、foreachループを乱用するのは間違っていることを強調することが重要です。それは危険でいっぱいです。念押し有難う。
追加された 著者 OldCurmudgeon,

もちろん、複数の並列イテレータをサポートすることができます。ファイルを複数回開くことができます。

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

    public BufferedReader(String fileName) {
      this.fileName = fileName;
      in = new InputStreamReader(new FileInputStream(fileName));
    }
    public Iterator iterator() {
        return new Iterator() {
            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
追加された
あなたは IOException を処理していません。
追加された 著者 McDowell,
良い考えです。私はファイルから実際には読んでいないと指定していたはずです。私はInputStreamだけを持っています。これは、たとえば、ネットワークソケットから直接読み取る場合です。
追加された 著者 Stefan,
また、すべてのデータをArrayListに読み込み、BufferedReaderでそのリストを読み込むこともできます。それからあなたは求めることができます。とにかくIterableを実装するだけです。 forループはiteratorメソッドを1回だけ呼び出します。だから問題はないはずです。
追加された 著者 SpiderPig,