use - list java for each




Formas de iterar sobre uma lista em Java (8)

As três formas de loop são quase idênticas. O loop for aprimorado:

for (E element : list) {
    . . .
}

é, de acordo com a Especificação da Linguagem Java , idêntico em efeito ao uso explícito de um iterador com um loop for tradicional. No terceiro caso, você só pode modificar o conteúdo da lista removendo o elemento atual e somente se fizer isso através do método remove do próprio iterador. Com iteração baseada em índice, você está livre para modificar a lista de qualquer maneira. No entanto, adicionar ou remover elementos que vêm antes do índice atual corre o risco de fazer com que o loop ignore elementos ou processe o mesmo elemento várias vezes; você precisa ajustar o índice de loop corretamente quando fizer essas alterações.

Em todos os casos, element é uma referência ao elemento de lista atual. Nenhum dos métodos de iteração faz uma cópia de qualquer coisa na lista. As alterações no estado interno do element sempre serão vistas no estado interno do elemento correspondente na lista.

Essencialmente, existem apenas duas maneiras de iterar em uma lista: usando um índice ou usando um iterador. O loop for aprimorado é apenas um atalho sintático introduzido no Java 5 para evitar o tédio de definir explicitamente um iterador. Para ambos os estilos, você pode chegar a variações essencialmente triviais usando for , while ou do while blocos, mas todos eles se resumem à mesma coisa (ou melhor, duas coisas).

EDIT: Como @ iX3 aponta em um comentário, você pode usar um ListIterator para definir o elemento atual de uma lista enquanto você está iterando. Você precisaria usar List#listIterator() invés de List#iterator() para inicializar a variável de loop (que, obviamente, teria que ser declarada como um ListIterator vez de um Iterator ).

Sendo um pouco novo para a linguagem Java, 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 objeto de List<E> list , eu sei das seguintes maneiras de percorrer todos os elementos:

Basic for loop (claro, há equivalência while / do while loops também)

// 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 apontou, este formulário é uma escolha ruim para iterar sobre List s, porque a implementação real do método get pode não ser tão eficiente quanto ao usar um Iterator . Por exemplo, as implementações de LinkedList devem atravessar todos os elementos que precedem i para obter o i-ésimo elemento.

No exemplo acima, não há como a implementação de List "salvar seu local" para tornar as iterações futuras mais eficientes. Para uma ArrayList , isso realmente não importa, porque a complexidade / custo de get é tempo constante (O (1)), enquanto que para uma LinkedList é proporcional ao tamanho da lista (O (n)).

Para obter mais informações sobre a complexidade computacional das implementações de Collections internas, verifique essa questão .

Enhanced for loop (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

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 mapeamento da API Stream do Java 8 (veja a resposta do @ i_am_zero).)

No Java 8, as classes de coleção que implementam Iterable (por exemplo, todas as List s) agora têm um método forEach , que pode ser usado em vez da for demonstrada 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 alguma?

(BTW, meu interesse não se origina de um desejo de otimizar o desempenho ; só quero saber quais formulários estão disponíveis para mim como desenvolvedor.)


Certo, muitas alternativas estão listadas. O mais fácil e mais limpo seria apenas usando o aprimorado for declaração como abaixo. A Expression é de algum tipo iterável.

for ( FormalParameter : Expression ) Statement

Por exemplo, para percorrer os ids da List <String>, podemos simplesmente,

for (String str : ids) {
    // Do something
}

Exemplo de cada tipo listado na pergunta:

ListIterationExample.java

import java.util.*;

public class ListIterationExample {

     public static void main(String []args){
        List<Integer> numbers = new ArrayList<Integer>();

        // populates list with initial values
        for (Integer i : Arrays.asList(0,1,2,3,4,5,6,7))
            numbers.add(i);
        printList(numbers);         // 0,1,2,3,4,5,6,7

        // replaces each element with twice its value
        for (int index=0; index < numbers.size(); index++) {
            numbers.set(index, numbers.get(index)*2); 
        }
        printList(numbers);         // 0,2,4,6,8,10,12,14

        // does nothing because list is not being changed
        for (Integer number : numbers) {
            number++; // number = new Integer(number+1);
        }
        printList(numbers);         // 0,2,4,6,8,10,12,14  

        // same as above -- just different syntax
        for (Iterator<Integer> iter = numbers.iterator(); iter.hasNext(); ) {
            Integer number = iter.next();
            number++;
        }
        printList(numbers);         // 0,2,4,6,8,10,12,14

        // ListIterator<?> provides an "add" method to insert elements
        // between the current element and the cursor
        for (ListIterator<Integer> iter = numbers.listIterator(); iter.hasNext(); ) {
            Integer number = iter.next();
            iter.add(number+1);     // insert a number right before this
        }
        printList(numbers);         // 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15

        // Iterator<?> provides a "remove" method to delete elements
        // between the current element and the cursor
        for (Iterator<Integer> iter = numbers.iterator(); iter.hasNext(); ) {
            Integer number = iter.next();
            if (number % 2 == 0)    // if number is even 
                iter.remove();      // remove it from the collection
        }
        printList(numbers);         // 1,3,5,7,9,11,13,15

        // ListIterator<?> provides a "set" method to replace elements
        for (ListIterator<Integer> iter = numbers.listIterator(); iter.hasNext(); ) {
            Integer number = iter.next();
            iter.set(number/2);     // divide each element by 2
        }
        printList(numbers);         // 0,1,2,3,4,5,6,7
     }

     public static void printList(List<Integer> numbers) {
        StringBuilder sb = new StringBuilder();
        for (Integer number : numbers) {
            sb.append(number);
            sb.append(",");
        }
        sb.deleteCharAt(sb.length()-1); // remove trailing comma
        System.out.println(sb.toString());
     }
}

No java 8 você pode usar o método List.forEach() com lambda expression para iterar em uma lista.

import java.util.ArrayList;
import java.util.List;

public class TestA {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("Apple");
        list.add("Orange");
        list.add("Banana");
        list.forEach(
                (name) -> {
                    System.out.println(name);
                }
        );
    }
}

O loop básico não é recomendado, pois você não conhece a implementação da lista.

Se isso fosse um LinkedList, cada chamada para

list.get(i)

seria iterar sobre a lista, resultando em complexidade de tempo N ^ 2.


Para uma pesquisa inversa, você deve usar o seguinte:

for (ListIterator<SomeClass> iterator = list.listIterator(list.size()); iterator.hasPrevious();) {
    SomeClass item = iterator.previous();
    ...
    item.remove(); // For instance.
}

Se você quiser saber uma posição, use iterator.previousIndex (). Também ajuda a escrever um loop interno que compara duas posições na lista (os iteradores não são iguais).


Você pode usar forEach partir do Java 8:

 List<String> nameList   = new ArrayList<>(
            Arrays.asList("USA", "USSR", "UK"));

 nameList.forEach((v) -> System.out.println(v));

Você sempre pode alternar o primeiro e o terceiro exemplos com um loop while e um pouco mais de código. Isso lhe dá a vantagem de poder usar o do-while:

int i = 0;
do{
 E element = list.get(i);
 i++;
}
while (i < list.size());

Claro, esse tipo de coisa pode causar um NullPointerException se o list.size () retornar 0, porque ele sempre é executado pelo menos uma vez. Isso pode ser corrigido testando se o elemento é nulo antes de usar seus atributos / métodos. Ainda assim, é muito mais simples e fácil usar o loop for





iteration