Quando devo aceitar um parâmetro de Iterable vs. Collection em Java?

Quais são as considerações sobre o uso de Iterable vs. Collection em Java?

Por exemplo, considere implementar um tipo que esteja preocupado principalmente em conter uma coleção de Foo s e alguns metadados associados. O construtor deste tipo permite a boot única da lista de objects. (Os metadados podem ser definidos posteriormente.) Que tipo esse construtor deve aceitar? Iterable , ou Collection ?

Quais são as considerações para esta decisão?

Seguindo o padrão estabelecido pelos tipos de biblioteca, como ArrayList (que pode ser inicializado a partir de qualquer Collection , mas não um Iterable ) levaria-me a usar Collection .

Mas por que não aceitar o Iterable , dado que isso é suficiente para as necessidades de boot? Por que exigir um nível mais alto de funcionalidade ( Collection ) do consumidor, do que o estritamente necessário ( Iterable )?

Muitos dos tipos de coleção existiam antes de Iterable (que foi introduzido apenas em 1.5) – havia poucas razões para adicionar um construtor para aceitar Iterable assim como Collection mas alterar o construtor existente teria sido um quebrando a mudança.

Pessoalmente, eu usaria o Iterable se isso permitir que você faça tudo o que quiser. É mais flexível para os chamadores e, em particular, permite que você faça filtragem / projeção / etc relativamente fácil usando o Google Java Collections (e, sem dúvida, bibliotecas semelhantes).

Um Iterable produz objects Iterator . Um object Iterator , por definição, itera . Observe que a interface Iterator não faz nenhuma promise sobre quantas vezes o next() pode ser chamado antes que o hasNext() retorne false . Um Iterator poderia iterar sobre valores Integer.MAX_VALUE + 1 antes que seu método hasNext() retornasse false .

No entanto, uma Collection é uma forma especial de Iterable . Como uma Collection não pode ter mais que os elementos Integer.MAX_VALUE (em virtude do método size() ), presume-se, naturalmente, que seus objects Iterator não serão Integer.MAX_VALUE elementos.

Portanto, ao aceitar uma Collection vez de uma Iterable , sua class pode ter alguma garantia sobre quantos elementos estão sendo passados. Isso é especialmente desejável se sua class for ela própria uma Collection .

Apenas meus dois centavos…

Use a interface mais geral que você puder. Já que tudo o que você vai fazer é iterar, então eu diria que Iterable é o caminho a seguir (já que permite iteradores preguiçosos, etc.). Você não se importa de onde o iterador está vindo, então não o restrinja mais do que o necessário.

Os usuários do Spring Data JPA descobrirão que os Repositories retornam collections do tipo Iterable.

Em projetos nos quais trabalhei no passado que usam o Spring , descobri que a necessidade de operar em uma Coleção após a recuperação geralmente dita que Iterable é usado na camada de negócios em vez de Collection em ordem para selecionar um object T da coleção.

Todas as Coleções são Iterable (ou seja, as interfaces que estendem a interface da Collection , portanto, não Map !), Portanto, usar Iterable na camada de negócios é meramente um caso de se referir a uma Coleção por seu tipo super e ainda permitir o uso de para iterar.

Se você precisar manipular o conteúdo de uma coleção, um método de conveniência permitiria que você preenche uma nova Collection , para que você possa fazer uso de contains() , remove() , etc com os dados da coleção original.

Como alternativa, os methods de conveniência são fornecidos para essa finalidade por APIs populares de terceiros, como o Google Guava e o Apache Commons.

Alguns construtores, por exemplo, ArrayList (Collection c), usam o método toArray () de Collection para eficiência.

Veja “Por que tanta ênfase em Iteradores e Iteráveis?” no Google Collection FAQ para um argumento decente para preferir Iteradores, especialmente ao lidar com muitos dados. Uma analogia que pode ajudar é pensar na diferença entre os cursores somente leitura somente para frente e os cursores roláveis.

Se você optar por Coleção, sua class poderá ser inicializada somente a partir de uma coleção, se você optar por Iterable, poderá inicializar a partir de qualquer coleção ou iterável.

Como o esforço e o desempenho de ambos serão os mesmos, faz todo o sentido aceitar Iterable no construtor.

De acordo com o princípio da menor surpresa, você deve emular o padrão de coleta Java e obter um argumento construtor Collection. Isso tornará as pessoas que vêm depois de você um pouco menos confusas.

Você está correto, pois é considerado uma boa prática pedir a forma mais geral do que você precisa.