Wie andere gesagt haben, kann ein Iterable mehrmals aufgerufen werden, wobei bei jedem Aufruf ein neuer Iterator zurückgegeben wird. Ein Iterator wird nur einmal verwendet. Sie sind also verwandt, dienen aber unterschiedlichen Zwecken. Frustrierenderweise funktioniert die "compact for" -Methode jedoch nur mit einer iterierbaren Methode.
Was ich im Folgenden beschreiben werde, ist eine Möglichkeit, das Beste aus beiden Welten zu haben - die Rückgabe einer Iterable (für eine bessere Syntax), selbst wenn die zugrunde liegende Datenfolge einmalig ist.
Der Trick besteht darin, eine anonyme Implementierung des Iterable zurückzugeben, die die Arbeit tatsächlich auslöst. Anstatt also die Arbeit zu erledigen, die eine einmalige Sequenz generiert, und dann einen Iterator darüber zurückzugeben, geben Sie eine Iterable zurück, die bei jedem Zugriff die Arbeit wiederholt. Das mag verschwenderisch erscheinen, aber oft wird das Iterable ohnehin nur einmal aufgerufen, und selbst wenn Sie es mehrmals aufrufen, hat es dennoch eine vernünftige Semantik (im Gegensatz zu einem einfachen Wrapper, der einen Iterator wie ein Iterable "aussehen" lässt, hat dies gewonnen). t bei zweimaliger Verwendung fehlschlagen).
Angenommen, ich habe ein DAO, das eine Reihe von Objekten aus einer Datenbank bereitstellt, und ich möchte über einen Iterator Zugriff darauf gewähren (z. B. um zu vermeiden, dass alle Objekte im Speicher erstellt werden, wenn sie nicht benötigt werden). Jetzt könnte ich einfach einen Iterator zurückgeben, aber das macht die Verwendung des zurückgegebenen Werts in einer Schleife hässlich. Also wickle ich stattdessen alles in eine 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();
}
};
}
}
Dies kann dann in Code wie folgt verwendet werden:
class DaoUser {
private MetricDao dao;
for (Metric existing : dao.loadAll()) {
// do stuff here...
}
}
Dadurch kann ich die kompakte for-Schleife verwenden und gleichzeitig die inkrementelle Speichernutzung beibehalten.
Dieser Ansatz ist "faul" - die Arbeit wird nicht erledigt, wenn die Iterable angefordert wird, sondern erst später, wenn der Inhalt wiederholt wird - und Sie müssen sich der Konsequenzen bewusst sein. Im Beispiel mit einem DAO bedeutet dies, dass die Ergebnisse innerhalb der Datenbanktransaktion durchlaufen werden.
Es gibt also verschiedene Vorbehalte, aber dies kann in vielen Fällen immer noch eine nützliche Redewendung sein.