2009-07-21 6 views
58

Was sind die Überlegungen zur Verwendung von Iterable<T> vs. Collection<T> in Java?Wann sollte ich einen Parameter von Iterable <T> vs. Sammlung <T> in Java akzeptieren?

Sie können beispielsweise einen Typ implementieren, der in erster Linie eine Sammlung von Foo s und einige zugehörige Metadaten enthält. Der Konstruktor dieses Typs erlaubt eine einmalige Initialisierung der Objektliste. (Die Metadaten können später festgelegt werden.) Welchen Typ sollte dieser Konstruktor akzeptieren? Iterable<Foo> oder Collection<Foo>?

Was sind die Überlegungen für diese Entscheidung?

dem Muster folgend von Bibliothekstypen wie ArrayList dargelegt (die von jedem Collection initialisiert werden kann, aber nicht ein Iterable) würde mich führen Collection<Foo> zu verwenden.

Aber warum nicht akzeptieren Iterable<Foo>, vorausgesetzt, das ist ausreichend für die Initialisierung braucht? Warum vom Kunden ein höheres Maß an Funktionalität (Collection) verlangen als das, was unbedingt notwendig ist (Iterable)?

+2

Es gibt einen tollen Artikel [hier] [1] dazu. [1]: http://www.artima.com/weblogs/viewpost.jsp?thread=119193 – amischiefr

Antwort

53

Viele der Sammlungstypen existierten, bevor Iterable<T> (die nur in 1,5 eingeführt wurde) - gibt es wenig Grund, ein Konstruktor hinzufügen zu akzeptieren Iterable<T>sowieCollection<T> aber die vorhandene Konstruktor zu ändern wäre ein Bruch Änderung gewesen.

Persönlich würde ich Iterable<T> verwenden, wenn Sie damit alles tun können, was Sie wollen. Es ist flexibler für Anrufer, und insbesondere können Sie relativ einfache Filterung/Projektion/etc mit den Google Java Collections (und ohne Zweifel ähnliche Bibliotheken) tun.

+0

Sie sagen, es wäre eine "bahnbrechende Veränderung". Was würde brechen, wenn (sagen wir) der ArrayList-Konstruktorparameter von Collection in Iterable geändert wurde? – finnw

+16

@finnw: Es wäre Quellkompatibel, aber nicht binärkompatibel: vorhandene (kompilierte) Klassen, die den aktuellen Konstruktor verwenden, würden brechen (da sie den Collection-param-Konstruktor explizit aufrufen) und müssen neu kompiliert werden. –

1

Nach dem Prinzip der geringsten Überraschung sollten Sie das Java-Sammlungsmuster emulieren und einen Collection-Konstruktor arg verwenden. Es wird die Leute, die nach dir kommen, etwas weniger verwirrt machen.

+7

Ich stimme nicht zu - Iterable lässt Sie weiterhin Sammlungen als Argumente nehmen, aber wie John sagt, können Sie in anderen Klassen weitergeben das lässt Sie über ihre Elemente treten. Wenn das alles ist, was Sie brauchen, ist es eine viel bessere Option. Ihre Javadocs sollten das Argument trotzdem dokumentieren, und wenn die Leute, die hinter Ihnen her sind, von Java-Kernklassen verwirrt sind, gibt es wahrscheinlich tiefere Probleme. ;-) –

+3

Ich bin bei Paul. Ich sehe kaum jemals in unseren eigenen Klassen oder in Bibliotheken. Ich sehe Sammlung mehr und Liste am häufigsten. Ich denke, es gibt eine Logik hinter der Wahl von Iterable, aber ich denke, das aktuelle Idiom ist Sammlungen. Vielleicht sollte es Iterables sein, und vielleicht wird es eines Tages auch sein, aber für den Moment wäre ich weniger überrascht von einer Sammlung. –

+1

** BOO !! ** –

-1

Sie haben Recht, da es als gute Praxis gilt, nach der allgemeinsten Form dessen zu fragen, was Sie brauchen.

8

Verwenden Sie die allgemeinste Schnittstelle, die Sie können. Da alles, was Sie tun werden, iterieren wird, würde ich sagen, Iterable ist der Weg zu gehen (da es faule Iteratoren usw. erlaubt). Es ist Ihnen egal, woher der Iterator kommt, also beschränken Sie ihn nicht mehr als nötig.

2

Wenn Sie auf Sammlung zugreifen, kann Ihre Klasse nur aus einer Sammlung initialisiert werden. Wenn Sie Iterable verwenden, können Sie entweder aus einer Sammlung oder iterierbar initialisieren.

Da der Aufwand und die Leistung für beide identisch sind, ist es absolut sinnvoll, Iterable im Konstruktor zu akzeptieren.

14

Ein Iterable produziert Iterator Objekte. Ein Iterator Objekt per Definition iteriert. Beachten Sie, dass die Iterator-Schnittstelle kein Versprechen gibt, wie oft aufgerufen werden kann, bevor hasNext()false zurückgibt. Ein Iterator könnte möglicherweise über Integer.MAX_VALUE + 1 Werte iterieren, bevor seine hasNext() Methode false zurückgibt.

Eine Collection ist jedoch eine spezielle Form von Iterable. Da ein Collection nicht mehr als Integer.MAX_VALUE Elemente haben kann (aufgrund der Methode size()), wird natürlich angenommen, dass seine Iterator Objekte nicht über diese vielen Elemente iterieren werden.

Durch die Annahme einer Collection anstelle einer Iterable kann Ihre Klasse eine gewisse Garantie dafür haben, wie viele Elemente übergeben werden. Dies ist besonders wünschenswert, wenn Ihre Klasse selbst eine Collection ist.

Nur meine zwei Cents ...

+4

Das verbietet ziemlich * unvernünftige * iterables auf Kosten von auch Nichtannahme, völlig angemessene iterables. –

+11

Und tatsächlich kann eine 'Collection' auch größer sein als Interger.MAX_VALUE, dann gibt die Size-Methode nur Integer.MAX_VALUE zurück. Der Vorteil einer 'Collection' ist meistens die' size() 'Methode (alles andere kann über Iterator und Größe implementiert werden, wie AbstractCollection zeigt), also benutze eine Collection **, wenn du die Größe vor dem Iterieren benötigst **, nicht wenn du nur iterieren willst. –

+1

@ Paŭlo: Wow, ich wusste nicht, dass 'Collection.size()' '' Integer.MAX_VALUE' zurückgibt, wenn es mehr als diese vielen Elemente enthält! –

4

Einige Konstruktoren, z.B. ArrayList (Collection c), verwenden Sie die ToArray() -Methode von Collection für Effizienz.

3

Siehe "Warum so viel Wert auf Iteratoren und Iterables?" auf der Google Collection FAQ für ein gutes Argument für die Bevorzugung von Iteratoren, vor allem, wenn es sich um eine Menge Daten handelt. Eine Analogie, die helfen könnte, ist der Unterschied zwischen Nur-Lese-Cursors und schreibbaren Cursorn.

7

Benutzer von Spring Data JPA werden feststellen, dass die Repositories return Sammlungen von Typ Iterable<T>.

auf Projekten, die ich habe in der Vergangenheit gearbeitet, die Spring verwenden, die ich gefunden habe, dass die Notwendigkeit an einer Sammlung für den Betrieb nach dem Abrufen hat oft diktiert, dass Iterable<T> in der Business-Schicht statt Collection<T> verwendet wird, um ein Objekt T aus der Sammlung auszuwählen.

Alle Kollektionen sind Iterable (dass die Schnittstellen sind, die die Collection Schnittstelle erweitern, so dass nicht Map!), So Iterable in der Business-Schicht verwenden, ist nur ein Fall von durch seinen Supertyp eine Sammlung beziehen und immer noch erlaubt die Verwendung von for-each zu iterieren.

Wenn Sie den Inhalt einer Sammlung bearbeiten müssen, eine bequeme Methode erlaubt es dir, ein neues Collection zu füllen, so können Sie nutzen , remove() usw. mit den ursprünglichen Sammlungsdaten zu machen.

Alternativ werden Komfortmethoden von beliebten Drittanbieter-APIs wie Google Guava und Apache Commons für diesen Zweck bereitgestellt.

Verwandte Themen