Maneiras de iterar sobre uma lista em Java
Sendo algo novo na linguagem Java I'estou tentando me familiarizar com todas as formas (ou pelo menos as não-patológicas) que se pode iterar através de uma lista (ou talvez outras coleções) e as vantagens ou desvantagens de cada uma.
Dado um List list
object, eu conheço as seguintes formas de fazer loop através de todos os elementos:
Basic for loop (claro, lá're equivalente while
/ do while
loops as well)
// Not recommended (see below)!
for (int i = 0; i < list.size(); i++) {
E element = list.get(i);
// 1 - can call methods of element
// 2 - can use 'i' to make index-based calls to methods of list
// ...
}
Nota: Como @amarseillan assinalou, esta forma é uma má escolha
para iterar sobre a "Lista", porque a implementação real do
o método 'get' pode não ser tão eficiente como quando se utiliza um 'Iterator'.
Por exemplo, implementações de LinkedList
devem atravessar todas as
os elementos que precedem o i para obter o i-ésimo elemento.
No exemplo acima não há's nenhuma maneira para a implementação da Lista
de
"salvar seu lugar" para tornar as futuras iterações mais eficientes.
Para uma ArrayList
não importa'porque a complexidade/custo do get
é tempo constante (O(1)) enquanto que para uma LinkedList
é proporcional ao tamanho da lista (O(n)).
Para mais informações sobre a complexidade computacional das implementações integradas de `Collections', confira esta pergunta.
Enhanced [for loop][for-each-loop-soop] (bem explicado nesta pergunta)
for (E element : list) {
// 1 - can call methods of element
// ...
}
Iterator
for (Iterator<E> iter = list.iterator(); iter.hasNext(); ) {
E element = iter.next();
// 1 - can call methods of element
// 2 - can use iter.remove() to remove the current element from the list
// ...
}
[ListIterator]listIterator
for (ListIterator<E> iter = list.listIterator(); iter.hasNext(); ) {
E element = iter.next();
// 1 - can call methods of element
// 2 - can use iter.remove() to remove the current element from the list
// 3 - can use iter.add(...) to insert a new element into the list
// between element and iter->next()
// 4 - can use iter.set(...) to replace the current element
// ...
}
Functional Java functional-java
list.stream().map(e -> e + 1); // Can apply a transformation function for e
Iterable.forEach]iterable-forEach, [Stream.forEach]stream.forEach, ...
(Um método de mapa do Java 8's Stream API (ver @i_am_zero's resposta)).
Em classes de coleção Java 8 que implementam Iterable
(por exemplo, todas as List
s) agora têm um método forEach
, que pode ser utilizado ao invés do for loop statement demonstrado acima. (Aqui está outra questão que fornece uma boa comparação).
Arrays.asList(1,2,3,4).forEach(System.out::println);
// 1 - can call methods of an element
// 2 - would need reference to containing object to remove an item
// (TODO: someone please confirm / deny this)
// 3 - functionally separates iteration from the action
// being performed with each item.
Arrays.asList(1,2,3,4).stream().forEach(System.out::println);
// Same capabilities as above plus potentially greater
// utilization of parallelism
// (caution: consequently, order of execution is not guaranteed,
// see [Stream.forEachOrdered][stream-foreach-ordered] for more
// information about this).
Que outras formas existem, se é que existem?
(BTW, o meu interesse não deriva em absoluto de um desejo de otimizar o desempenho; eu só quero saber que formas estão disponíveis para mim como desenvolvedor).
Exemplo de cada tipo listado na pergunta:
ListIterationExample.java
Eu não'não sei o que você considera patológico, mas deixe-me fornecer algumas alternativas que você não poderia ter visto antes:
Ou a sua versão recursiva:
Também, uma versão recursiva do clássico
for(int i=0...
:Eu os menciono porque você é " um pouco novo no Java" e isso pode ser interessante.
Você sempre poderia trocar o primeiro e terceiro exemplos com um laço de tempo e um pouco mais de código. Isto dá-lhe a vantagem de poder usar o do-while:
Claro, este tipo de coisa pode causar uma NullPointerException se o list.size() retornar 0, porque ele sempre é executado pelo menos uma vez. Isto pode ser corrigido testando se o elemento é nulo antes de usar seus atributos / métodos tho. Ainda assim, it's é muito mais simples e fácil de usar o loop for