Sendo um pouco novo para a linguagem Java, estou tentando me familiarizar com todas as maneiras (ou pelo menos as não-patológicas) em que se pode percorrer uma lista (ou talvez outras coleções) e as vantagens ou desvantagens de cada uma.
Dado um List<E> list
objeto, conheço as seguintes maneiras de percorrer todos os elementos:
Básico para loop (é claro, também existem equivalentes while
/ do while
loops)
// 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 o @amarseillan apontou, este formulário é uma má escolha para iterar sobre List
s, porque a implementação real do get
método pode não ser tão eficiente quanto ao usar um Iterator
. Por exemplo, as LinkedList
implementações devem atravessar todos os elementos anteriores a i para obter o i-ésimo elemento.
No exemplo acima, não há como a List
implementação "salvar seu lugar" para tornar as iterações futuras mais eficientes. Para um ArrayList
, isso realmente não importa, porque a complexidade / custo de get
é tempo constante (O (1)), enquanto para a LinkedList
é proporcional ao tamanho da lista (O (n)).
Para obter mais informações sobre a complexidade computacional das Collections
implementações internas, consulte esta pergunta .
Aprimorado para loop (explicado detalhadamente nesta pergunta )
for (E element : list) {
// 1 - can call methods of element
// ...
}
Iterador
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
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
// ...
}
Java funcional
list.stream().map(e -> e + 1); // Can apply a transformation function for e
Iterable.forEach , Stream.forEach , ...
(Um método de mapa da API Stream do Java 8 (consulte a resposta de @i_am_zero).)
No Java 8, as classes de coleção que implementam Iterable
(por exemplo, todos os List
s) agora têm um forEach
método, que pode ser usado em vez da instrução de loop for demonstrada acima. (Aqui está outra pergunta 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 maneiras existem, se houver?
(BTW, meu interesse não resulta de um desejo de otimizar o desempenho ; eu só quero saber quais formulários estão disponíveis para mim como desenvolvedor.)
List
interface é específica?