2011-12-18 28 views
3

可能性の重複:
Why is Java's Iterator not an Iterable?拡張forループがイテレータで機能しないのはなぜですか?

我々はすべてのJavaのを知っているがforループを拡張:

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

私は必要なものである:

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

Javaではこれを許可していません。 仕様がなぜこのような理由でサポートされていないのかというと、です。

私はファイル形式の種類の読者を書いている:

は、ここに私のユースケースです。このようなファイルには、読み取られるエントリが含まれています。この例では、私はBufferedReaderを再開発しようとしていて、私の要素はStringsであると仮定します。

私はのような醜いコードを書くために私を強制的に元BufferedReaderのAPIスタイルで、非常に不幸だ:私はむしろ当然のことながら

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

のような素敵な何かを持っていると思います

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

BufferedReaderIterable<String>を実装させることができます。しかし、これは、数回呼び出されるかもしれないiterator()メソッドがあることを意味します。私はファイルを探すことができないので、私は実際には複数の並列イテレータをサポートすることはできません。

私のBufferedReaderを実装すると、Iterable<String>の代わりにIterator<String>が実装されているようです。しかし、私はあなたがより多くのそして一度ファイルを開くことができます。あなたは、複数の並列イテレータをサポートすることができます。もちろん、

+0

アドバンストループが「イテレータ」メソッドを複数回呼び出すかどうか確認しましたか?私はそれが一度だけ行うと仮定します。 –

+1

見出しの質問への答えは "それが言語が定義されている方法なので"です。 –

+2

もう一度、私はそれが重複していることに同意します。私は2つのインターフェースの相違点をよく知っています。私はなぜこの違いがforループに関して関係があるのか​​を尋ねています。私はまた、このように指定されていることを認識しています。私はなぜそれがこのように指定されたのだろうと思っています。 – Stefan

答えて

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. 

} 
を与えることができるを取ることが許されていた場合0

私はそれが事をより簡単にするだろうと承知していますが、あなたがすべてのの記入項目をカバーしたことを知ることはないので、重大なバグを招くこともあります。

// 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(); 
    } 
}) { 
} 

厄介ですが、それはうまくいくはずです。

+0

あなたは静的な方法であなたのハックのよりクリーンな実装を行うことができます - 私は[関連する質問]に追加しました(http://stackoverflow.com/a/8555153/304) – McDowell

+0

良い点Paul。文法的にはエレガントですが、ファイルの途中で開始するとforeachのセマンティクスが変更されます。シーク不可能なストリームからの読み込みはforeachセマンティクスに追いついていないので、回避してもそれを使用するのは間違いでしょう。 – Stefan

+0

@McDowell - ありがと...私はマシン上で今はjava 5を持っていないので、テストできませんでした。それはあなたが一度だけ "反復子"を作った方法は賢いです。 @Lawnmower - foreachループを乱用するのは間違っていることを強調することが重要です。特に 'thister'を返すことで' Iterator''Iterable'を作ることが重要です。それは危険でいっぱいです。念押し有難う。 – OldCurmudgeon

1

:-(forステートメントを使用することはできません。

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; 
      } 
     } 
    } 
} 
+0

あなたは 'IOException'を扱っていません – McDowell

+0

それは良い考えです。私はファイルから実際には読んでいないと指定していたはずです。私はInputStreamだけを持っています。これは、たとえば、ネットワークソケットから直接読み取る場合です。 – Stefan

+0

また、すべてのデータをArrayListに読み込み、BufferedReaderでそのリストを読み取ることもできます。それからあなたは求めることができます。とにかくIterableを実装するだけです。 forループはiteratorメソッドを1回だけ呼び出します。だから問題はないはずです。 – SpiderPig

関連する問題