2009-07-21 19 views
58

¿Cuáles son las consideraciones de usar Iterable<T> frente a Collection<T> en Java?¿Cuándo debería aceptar un parámetro de Iterable <T> frente a Collection <T> en Java?

Por ejemplo, considere la implementación de un tipo que se ocupa principalmente de contener una colección de Foo s, y algunos metadatos asociados. El constructor de este tipo permite la inicialización por única vez de la lista de objetos. (Los metadatos se pueden configurar más adelante.) ¿Qué tipo debe aceptar este constructor? Iterable<Foo>, o Collection<Foo>?

¿Cuáles son las consideraciones para esta decisión?

Siguiendo el patrón establecido por tipos de biblioteca tales como ArrayList (que puede ser inicializado desde cualquier Collection, pero no un Iterable) me llevaría a utilizar Collection<Foo>.

¿Pero por qué no aceptar Iterable<Foo>, dado que esto es suficiente para las necesidades de inicialización? ¿Por qué exigir un nivel más alto de funcionalidad (Collection) del consumidor, que lo estrictamente necesario (Iterable)?

+2

Hay un gran artículo [aquí] [1] sobre esto. [1]: http://www.artima.com/weblogs/viewpost.jsp?thread=119193 – amischiefr

Respuesta

53

Muchos de los tipos de colección existía antes Iterable<T> (que sólo se introdujo en 1.5) - había pocas razones para agregar un constructor para aceptar Iterable<T>, así comoCollection<T> pero cambiando el constructor existente habría sido un cambio importante.

Personalmente, usaría Iterable<T> si eso le permite hacer todo lo que quiera. Es más flexible para las personas que llaman y, en particular, le permite hacer relativamente fácil filtrado/proyección/etc. usando Google Java Collections (y sin dudas bibliotecas similares).

+0

Usted dice que sería un "cambio radical". ¿Qué se rompería si (por ejemplo) el parámetro del constructor ArrayList se cambiara de la Colección a Iterable ? – finnw

+16

@finnw: Sería compatible con la fuente, pero no compatible con binario: las clases existentes (compiladas) que usan el constructor actual se romperían (ya que llaman al Collection-param-constructor explícitamente) y necesitan ser recompiladas. –

1

De acuerdo con el principio de menor sorpresa, debe emular el patrón de recopilación de Java y tomar un arg de constructor de colecciones. Hará que las personas que te siguen desconfíen un poco.

+7

No estoy de acuerdo - Iterable todavía le permite tomar Colecciones como argumentos, pero como dice John le permite pasar en otras clases que te permite pasar por encima de sus elementos. Si esta es toda la funcionalidad que necesita, es una opción mucho mejor. Sus Javadocs deben documentar el argumento de todos modos, y si las personas que le siguen están desconcertadas por las clases principales de Java, probablemente haya problemas más profundos. ;-) –

+3

Estoy con Paul. Casi nunca veo Iterable, en nuestras propias clases o en bibliotecas. Veo Colección más y Lista con más frecuencia. Creo que hay una lógica detrás de la elección de Iterable, pero creo que la expresión actual es Colecciones. Tal vez debería ser Iterables, y tal vez lo será, algún día, pero por ahora, me sorprendería menos una Colección. –

+1

** ¡¡¡BOO !! ** –

-1

Está en lo correcto, ya que se considera una buena práctica pedir la forma más general de lo que necesita.

8

Utilice la interfaz más general que pueda. Como todo lo que vas a hacer es iterar, entonces diría que Iterable es el camino a seguir (ya que permite iteradores vagos, etc.). No le importa de dónde viene el iterador, por lo tanto, no lo restrinja más de lo necesario.

2

Si elige Colección, su clase se puede inicializar de una colección solamente, si elige Iterable, puede inicializar desde una colección o iterable.

Como el esfuerzo y el rendimiento para ambos va a ser el mismo, tiene mucho sentido aceptar Iterable en el constructor.

14

Un Iterable produce Iterator objetos. Un objeto Iterator, por definición, itera. Tenga en cuenta que la interfaz Iterator no promete cuántas veces se puede llamar al next() antes de hasNext() devuelve false. Un Iterator podría iterar sobre valores de Integer.MAX_VALUE + 1 antes de que su método hasNext() devuelva false.Sin embargo, Collection es una forma especial de Iterable. Como un Collection no puede tener más de Integer.MAX_VALUE elementos (en virtud del método size()), se supone que sus objetos Iterator no iterarán sobre estos muchos elementos.

Por lo tanto, al aceptar un Collection en lugar de un Iterable, su clase puede tener alguna garantía sobre cuántos elementos se están pasando. Esto es especialmente deseable si la clase es en sí mismo un Collection.

Sólo mis dos centavos ...

+4

Que rechaza los elementos bastante razonables * irrazonables * a expensas de también rechazar los elementos no recolectados, completamente razonables. –

+11

Y, de hecho, una 'Colección' también puede ser más grande que Interger.MAX_VALUE, luego el método de tamaño simplemente devuelve Integer.MAX_VALUE. La ventaja de una 'Colección' es principalmente el método' size() '(todo lo demás puede implementarse sobre Iterator y tamaño, como lo muestra AbstractCollection), así que use una Colección ** cuando necesite el tamaño antes de iterar **, no cuando solo quieres iterar. –

+1

@ Paŭlo: ¡Vaya, no sabía que 'Collection.size()' devuelve 'Integer.MAX_VALUE' si contiene más que muchos elementos! –

4

Algunos constructores, por ejemplo, ArrayList (Colección c), use el método toArray() de Collection for efficiency.

3

Consulte "¿Por qué tanto énfasis en Iteradores e Iterables?" en el Google Collection FAQ para un argumento decente para preferir iteradores, especialmente cuando se trata de una gran cantidad de datos. Una analogía que podría ayudar es pensar la diferencia entre los cursores solo de lectura directa y los cursores desplazables.

7

Los usuarios de Spring Data JPA encontrarán que los Repositories colecciones de retorno de tipo Iterable<T>.

En los proyectos que he trabajado en el pasado que utilizan Spring, he encontrado que la necesidad de operar en una colección después de la recuperación tiene a menudo dicta que Iterable<T> se utiliza en la capa empresarial en lugar de Collection<T> para seleccionar un objeto T de la colección.

Todas las colecciones son Iterable (es decir, las interfaces que extienden la interfaz Collection, por lo que no Map!), Así que usar Iterable en la capa de negocio es simplemente un caso de referirse a una colección de su tipo super y todavía permite el uso de for-each para iterar.

Si necesita manipular el contenido de una colección, un método de conveniencia le permitiría rellenar un nuevo Collection, para que pueda hacer uso de , remove(), etc, con los datos de la colección originales.

Como alternativa, los métodos de conveniencia se proporcionan para este propósito por API de terceros populares como Google Guava y Apache Commons.

Cuestiones relacionadas