Preciso descobrir o número de elementos em um Iterable
em Java. Eu sei que posso fazer isso:
Iterable values = ...
it = values.iterator();
while (it.hasNext()) {
it.next();
sum++;
}
Eu também poderia fazer algo assim, porque não preciso mais dos objetos no Iterable:
it = values.iterator();
while (it.hasNext()) {
it.remove();
sum++;
}
Um benchmark de pequena escala não mostrou muita diferença de desempenho, algum comentário ou outras ideias para este problema?
remove()
sem ligar denext()
antemão.Respostas:
TL; DR: Use o método utilitário
Iterables.size(Iterable)
da grande biblioteca Guava .Dos seus dois snippets de código, você deve usar o primeiro, porque o segundo removerá todos os elementos de
values
, portanto, ele fica vazio depois. Alterar a estrutura de dados de uma consulta simples como seu tamanho é muito inesperado.Para desempenho, isso depende de sua estrutura de dados. Se for, por exemplo, de fato um
ArrayList
, remover elementos do início (o que seu segundo método está fazendo) é muito lento (calcular o tamanho torna-se O (n * n) em vez de O (n) como deveria ser).Em geral, se houver a chance de que
values
seja realmente umCollection
e não apenas umIterable
, verifique e chamesize()
neste caso:if (values instanceof Collection<?>) { return ((Collection<?>)values).size(); } // use Iterator here...
A chamada para
size()
geralmente será muito mais rápido do que contar o número de elementos, e esse truque é exatamente oIterables.size(Iterable)
de goiaba faz por você.fonte
values
Se estiver trabalhando com o java 8, você pode usar:
Iterable values = ... long size = values.spliterator().getExactSizeIfKnown();
ele só funcionará se a fonte iterável tiver um tamanho determinado. A maioria dos Divisores para Coleções sim, mas você pode ter problemas se vier de um
HashSet
ou,ResultSet
por exemplo.Você pode verificar o javadoc aqui.
Se o Java 8 não for uma opção , ou se você não souber de onde vem o iterável, você pode usar a mesma abordagem da goiaba:
if (iterable instanceof Collection) { return ((Collection<?>) iterable).size(); } else { int count = 0; Iterator iterator = iterable.iterator(); while(iterator.hasNext()) { iterator.next(); count++; } return count; }
fonte
Talvez seja um pouco tarde, mas pode ajudar alguém. Encontrei um problema semelhante com
Iterable
em minha base de código e a solução foi usarfor each
sem chamar explicitamentevalues.iterator();
.int size = 0; for(T value : values) { size++; }
fonte
A rigor, Iterable não tem tamanho. Pense na estrutura de dados como um ciclo.
E pense em seguir a instância Iterable, Sem tamanho:
new Iterable(){ @Override public Iterator iterator() { return new Iterator(){ @Override public boolean hasNext() { return isExternalSystemAvailble(); } @Override public Object next() { return fetchDataFromExternalSystem(); }}; }};
fonte
Você pode converter seu iterável em uma lista e usar .size () nela.
Por motivos de clareza, o método acima exigirá a seguinte importação:
import com.google.common.collect.Lists;
fonte
Eu escolheria pelo
it.next()
simples motivo de quenext()
sua implementação é garantida, enquantoremove()
é uma operação opcional.fonte
remove
já foi apontado como a maneira errada de contar os elementos de umIterator
, então realmente não importa se o que não vamos fazer é implementado ou não.remove
é implementado, por que seria errado usá-lo? A propósito, votos negativos são tipicamente usados para respostas erradas ou respostas que dão conselhos ruins. Não consigo ver como essa resposta se qualifica para nada disso.java 8 e superior
StreamSupport.stream(data.spliterator(), false).count();
fonte
Quanto a mim, são apenas métodos diferentes. O primeiro deixa o objeto no qual você está iterando inalterado, enquanto os segundos o deixam vazio. A questão é o que você quer fazer. A complexidade da remoção é baseada na implementação de seu objeto iterável. Se você estiver usando coleções - apenas obtenha o tamanho proposto por Kazekage Gaara - geralmente é a melhor abordagem em termos de desempenho.
fonte
Por que você simplesmente não usa o
size()
método em seuCollection
computador para obter o número de elementos?Iterator
destina-se apenas a iterar, nada mais.fonte
Iterator
eIterable
. Veja a resposta votada para a forma correta.Em vez de usar loops e contar cada elemento ou usar uma biblioteca de terceiros, podemos simplesmente fazer o typecast do iterável em ArrayList e obter seu tamanho.
fonte