他の人が言ったように、Iterableは複数回呼び出すことができ、各呼び出しで新しいIteratorを返します。イテレータは一度だけ使用されます。したがって、それらは関連していますが、目的は異なります。ただし、イライラして「コンパクト」メソッドは、イテラブルでのみ機能します。
以下で説明するのは、両方の世界の利点を活かすための1つの方法です。基礎となるデータのシーケンスが1回限りでも、Iterableを返す(より良い構文の場合)。
トリックは、実際に作業をトリガーするIterableの匿名実装を返すことです。したがって、1回限りのシーケンスを生成する作業を行ってからIteratorを返す代わりに、アクセスされるたびに作業をやり直すIterableを返します。それは無駄に思えるかもしれませんが、とにかく一度Iterableを呼び出すのは1回だけであり、複数回呼び出す場合でも、合理的なセマンティクスを持っています(IteratorをIterableのように見える単純なラッパーとは異なり、これは2回使用すると失敗します)。
たとえば、データベースから一連のオブジェクトを提供するDAOがあり、イテレータを介してそのオブジェクトへのアクセスを提供したいとします(たとえば、不要な場合にメモリ内にすべてのオブジェクトを作成しないようにします)。これでイテレータを返すだけで済むようになりましたが、ループで戻り値を使用すると見苦しくなります。したがって、代わりにすべてをanon Iterableでラップします。
class MetricDao {
...
/**
* @return All known metrics.
*/
public final Iterable<Metric> loadAll() {
return new Iterable<Metric>() {
@Override
public Iterator<Metric> iterator() {
return sessionFactory.getCurrentSession()
.createQuery("from Metric as metric")
.iterate();
}
};
}
}
これは、次のようなコードで使用できます。
class DaoUser {
private MetricDao dao;
for (Metric existing : dao.loadAll()) {
// do stuff here...
}
}
これにより、メモリの増分使用を維持しながら、コンパクトなforループを使用できます。
このアプローチは「遅延」です。Iterableが要求されたときに作業が行われるのではなく、後でコンテンツが反復処理されたときにのみ行われます。その結果に注意する必要があります。DAOを使用した例では、データベーストランザクション内の結果を反復処理することを意味しています。
したがって、さまざまな注意事項がありますが、多くの場合、これは依然として有用なイディオムです。