qué - ¿Cuándo debería aceptar un parámetro de Iterable<T> frente a Collection<T> en Java?
metodos genericos java (9)
Algunos constructores, por ejemplo, ArrayList (Colección c), usan el método toArray () de Collection for efficiency.
¿Cuáles son las consideraciones sobre el uso de Iterable<T>
frente a Collection<T>
en Java?
Por ejemplo, considere implementar un tipo que esté principalmente relacionado con contener una colección de Foo
, 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?
Seguir el patrón establecido por los tipos de biblioteca como ArrayList
(que se puede inicializar desde cualquier Collection
, pero no con un Iterable
) me llevaría a utilizar Collection<Foo>
.
Pero, ¿por qué no acepta 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
)?
Consulte "¿Por qué tanto énfasis en Iteradores e Iterables?" en las Preguntas frecuentes de Google Collection sobre 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.
De acuerdo con el principio de menor sorpresa, debe emular el patrón de recolección de Java y tomar un arg de constructor de Colección. Hará que las personas que te siguen desconfíen un poco.
Estás en lo correcto, ya que se considera una buena práctica pedir la forma más general de lo que necesitas.
Los usuarios de Spring Data JPA
encontrarán que los Repositories
devuelven colecciones de tipo Iterable<T>.
En proyectos en los que he trabajado anteriormente que usan Spring
, he descubierto que la necesidad de operar en una colección después de la recuperación a menudo dicta que Iterable<T>
se usa en la capa empresarial en lugar de Collection<T>
en orden para seleccionar un Objeto T
de la colección.
Todas las Colecciones son Iterable
(es decir, las interfaces que extienden la interfaz de Collection
, entonces no Map
!), Por lo que usar Iterable
en la capa de negocios es simplemente un caso de referencia a una Colección por su super tipo y aún permite el uso de for-each
para iterar
Si necesita manipular el contenido de una colección, un método de conveniencia le permitirá completar una nueva Collection
, para que pueda usar contains()
, remove()
, etc. con los datos de la colección original.
Alternativamente, los métodos de conveniencia se proporcionan para este propósito por API de terceros populares, como Google Guava y Apache Commons.
Muchos de los tipos de colección existían antes de Iterable<T>
(que solo se introdujo en 1.5): había pocas razones para agregar un constructor para aceptar Iterable<T>
y Collection<T>
pero cambiar el constructor existente habría sido un rompiendo el cambio.
Personalmente, usaría Iterable<T>
si eso te permite hacer todo lo que quieras. Es más flexible para las personas que llaman y, en particular, le permite filtrar / proyectar / etc. relativamente fácil utilizando Google Java Collections (y sin duda bibliotecas similares).
Si elige Colección, su clase puede inicializarse desde 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.
Un Iterable
produce objetos Iterator
. Un objeto Iterator
, por definición, itera . Observe que la interfaz del Iterator
no promete cuántas veces se puede hasNext()
antes de que hasNext()
devuelva false
. Un Iterator
podría iterar sobre valores Integer.MAX_VALUE + 1
antes de que su método hasNext()
devuelva false
.
Sin embargo, una Collection
es una forma especial de Iterable
. Como una Collection
no puede tener más de elementos Integer.MAX_VALUE
(en virtud del método size()
), se supone que sus objetos Iterator
no se repetirán sobre estos muchos elementos.
Por lo tanto, al aceptar una Collection
lugar de una Iterable
, su clase puede tener alguna garantía sobre cuántos elementos se están transfiriendo. Esto es especialmente conveniente si su clase es en sí misma una Collection
.
Solo mis dos centavos ...
Usa la interfaz más general que puedas. 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.