Article image
Victor Carvalho
Victor Carvalho09/02/2024 17:54
Compartilhe

Funções Java - Entendendo o for-each loop

    Seja no dia a dia de trabalho ou nos estudos, iremos nos deparar com alguma situação onde devemos iterar uma collection, como um Array ou um Map, ou seja, percorrer tal collection item a item. Em alguns casos, é possível utilizarmos o laço de repetição *for*, entretanto, a partir do Java 8, foi introduzida uma forma mais curta e elegante de iterar collections: o for-Each. Neste artigo, iremos abordar algumas formas de implementação do for-Each, entender um pouco mais sobre essa função do Java, utilizando como exemplo um sistema de disparo de e-mail fictício para uma lista de e-mails.

    Entendendo o caso

    Vamos supor que temos uma lista de e-mail de clientes da nossa plataforma, e desejamos enviar para eles um e-mail notificando-os sobre a promoção que ocorrerá no próximo final de semana. O método responsável pelo envio do e-mail é o sendEmail da nossa classe imaginária, portanto devemos percorrer a referida lista e enviar para cada elemento desta. Dessa forma, podemos utilizar o seguinte caso:

    
    public class SendEmailExample {  
    // Método que fara a lógica ficcional de envio de email.  
    static String sendEmail(String email) {  
      return "Email enviado para: " + email;  
    }  
     
    public static void main(String[] args) {  
     
      var clientsEmails = new ArrayList<String>();  
      clientsEmails.add("cliente1@email.com");  
      clientsEmails.add("cliente2@email.com");  
      clientsEmails.add("cliente3@email.com");
    }
    

    Usando uma maneira mais simples, podemos percorrer essa lista com um for-loop da seguinte forma:

    public class SendEmailExample {  
    // Método que fara a lógica ficcional de envio de email.  
    static String sendEmail(String email) {  
      return "Email enviado para: " + email;  
    }  
     
    public static void main(String[] args) {  
     
      var clientsEmails = new ArrayList<String>();  
      clientsEmails.add("cliente1@email.com");  
      clientsEmails.add("cliente2@email.com");  
      clientsEmails.add("cliente3@email.com");  
     
      for (int i = 0; i < clientsEmails.size(); i++) {  
        System.out.println(sendEmail(clientsEmails.get(i)));  
      }  
     
    }  
    }
    

    Ou também utilizando o for-loop aprimorado, ficando dessa maneira:

    public class SendEmailExample {  
    // Método que fara a lógica ficcional de envio de email.  
    static String sendEmail(String email) {  
      return "Email enviado para: " + email;  
    }  
     
    public static void main(String[] args) {  
     
      var clientsEmails = new ArrayList<String>();  
      clientsEmails.add("cliente1@email.com");  
      clientsEmails.add("cliente2@email.com");  
      clientsEmails.add("cliente3@email.com");  
     
      for (String email: clientsEmails) {  
        System.out.println(email);  
      }  
    }  
    }
    

     E essa seria a saída, conforme esperado para ambos os casos:

      Email enviado para: client1@email.com
      Email enviado para: client2@email.com
      Email enviado para: client3@email.com
    

    Conhecendo o for-Each

    Como mencionado anteriormente, a partir do Java 8, foi implementada a função for-Each para as collections. Assim tornando o nosso código menos verboso. Vejamos como ficaria o exemplo acima com o uso do for-each:

    public class SendEmailExample {  
    // Método que fara a lógica ficcional de envio de email.  
    static String sendEmail(String email) {  
      return "Email enviado para: " + email;  
    }  
     
    public static void main(String[] args) {  
     
      var clientsEmails = new ArrayList<String>();  
      clientsEmails.add("cliente1@email.com");  
      clientsEmails.add("cliente2@email.com");  
      clientsEmails.add("cliente3@email.com");  
     
      clientsEmails.forEach(email -> System.out.println(sendEmail(email)));  
    }  
    }
    

    A função for-Each é um método público da classe ArrayList, e acessando-o, podemos ver que, na sua implementação, é usado o paradigma funcional. Bom, mas então uma função é um método e método é uma função? Vou deixar um outro artigo em que esse tema é melhor explicado. Inspecionando o for-Each, vemos que ele faz algumas validações de tamanho da lista que será percorrida e voilá! Temos dois laços de repetição for por debaixo dos panos.

    public void forEach(Consumer<? super E> action) {  
      Objects.requireNonNull(action);  
      final int expectedModCount = modCount;  
      final Object[] es = elementData;  
      final int size = this.size;  
      for (int i = 0; modCount == expectedModCount && i < size; i++)  
          action.accept(elementAt(es, i));  
      if (modCount != expectedModCount)  
          throw new ConcurrentModificationException();  
    }
    
    

    Entendendo a estrutura do for-Each

    Vamos voltar a olhar o exemplo do envio de e-mail que utilizamos acima e entender melhor o for-Each loop:

    clientsEmails.forEach(email -> System.out.println(sendEmail(email))); 
    

    Como o clientsEmails é um arraylist, conseguimos utilizar o loop através da notação ponto, e passamos o "e-mail" como o índice, ou seja, da mesma forma que passamos o string e-mail no for-loop aprimorado, porém utilizando-o como parâmetro. Logo após temos a lambda expression, que indica que um parâmetro retornará um valor, que no caso é o print do nosso método sendEmail. Como só temos um único método sendo executado, não há a necessidade de colocarmos chaves após o parâmetro, mas caso tivesse, poderíamos fazer desse jeito:

    
    clientsEmails.forEach(email -> { 
     System.out.println("Enviando email para: "+email); 
     System.out.println(sendEmail(email)); 
    });
    

    Também podemos utilizar o for-Each loop com o method reference, deixando de forma mais

    enxuta o nosso código.

    clientsEmails.forEach(SendEmailExample::sendEmail);
    

    No method reference, referenciamos que o loop irá iterar a lista, e para cada índice ele irá chamar o método sendEmail da nossa classe. Porém note que, diferentemente dos outros exemplos, não podemos adicionar outros métodos, assim como os prints dos exemplos acima. 

    Conclusão

    Vimos que, com o for-Each loop, podemos iterar listas com um código bem mais enxuto, trazendo assim uma maior compreensão em nosso projetos. Deixarei alguns links abaixo de materiais para que você possar aprofundar cada vez mais em seus estudos. Espero ter ajudado!

    Um guia sobre forEach (inglês) - https://www.baeldung.com/foreach-java

    Funções vs Métodos - https://pt.stackoverflow.com/questions/212265/fun%c3%a7%c3%a3o-e-m%c3%a9todo-s%c3%a3o-a-mesma-coisa/212272#212272

    Programação funcional com Java -https://www.devmedia.com.br/programacao-funcional-com-java/32176

    Compartilhe
    Comentários (2)

    CR

    Cainã Ribeiro - 15/02/2024 18:15

    muito boa a explicação, agora sim entendi como funciona!

    Matheus Paulino
    Matheus Paulino - 10/02/2024 09:16

    Melhor explicação que eu já vi, para todos os for de forma resumida e clara.