Java forEach: como usar o enhanced-for loop

As estruturas de repetição Java forEach ou, como também são conhecidas, enhanced-for loop, foram adicionadas a partir da quinta versão do Java. Trouxeram consigo facilidades para as pessoas desenvolvedoras durante a manipulação de arrays e coleções, possibilitando uma escrita de código mais limpa ao realizar a iteração desses elementos.

Muitos de nós, quando iniciamos no desenvolvimento Java, podemos ter alguns problemas para entender e, consequentemente, utilizar o forEach de maneira adequada, seguindo as instruções de melhores práticas da linguagem. Isso acontece por conta de vários fatores, como a diferença entre o laço for, o uso do for-each loop e do método forEach().

Pensando nessas dificuldades, trazemos, neste guia, as principais questões envolvidas nesses recursos de iteração e suas principais diferenças. Para isso, usamos alguns exemplos práticos, além de oferecer um ponto de vista teórico explicado de uma maneira mais simples de ser compreendida.

Então, prepare-se para entender de uma vez por todas o que é o Java forEach e em que pode colaborar para um desenvolvimento mais dinâmico de suas aplicações codadas em Java. Serão abordados os seguintes tópicos:

Prepare-se e vamos nessa!

O que é o Java forEach e para que serve?

A expressão de língua inglesa “for each” pode ser traduzida como “para cada”. Em Java, os métodos iteradores for-each e forEach(), explicando de maneira bem resumida, são usados para iteração de listas e coleções. Sua principal característica é a simplificação do loop for, deixando o código mais leve e fácil de ser lido pelas pessoas responsáveis pelo desenvolvimento e pela manutenção.

Não há alteração quanto à performance do programa em que um laço forEach é aplicado na maioria das vezes. Isso se deve ao fato de que seu funcionamento ocorre da mesma maneira da estrutura for — aquela mais convencional — durante o processamento do código.

Em alguns casos, no entanto, precisamos acessar coleções de estruturas de dados específicas, por exemplo. O uso do forEach(), como iterador, pode providenciar um processamento significativamente mais rápido para as operações.

Normalmente, usamos a estrutura for-each para que o laço for percorra todo o array, — essa é uma das suas principais funcionalidades. Fazendo isso, nos precavemos de problemas relacionados à manipulação das posições ocupadas pelos elementos de um array (como iniciar sua contagem pelo número 1,e não pelo 0, como fazem algumas pessoas) ou ocupar, sem querer, todas as posições durante o processo de iteração — e bugar nossa aplicação.

Qual a sintaxe do Java forEach?

A sintaxe do Java forEach loop consiste na identificação do tipo de estrutura dos dados utilizados, seguidos por dois pontos (:) — posteriormente, usamos a identificação do array ou da coleção que queremos utilizar, assim:

for(<Tipo> <identificação> : <array ou coleção>) {
        <comando>
}

Repare que os dois pontos (:) podem ser lidos como “em”. No caso do exemplo acima, poderíamos ler o código da seguinte maneira: para cada elemento contido em um array, uma instrução é dada.

Ela seria equivalente ao uso do laço for normal, como no seguinte exemplo:

for (int i=0; i<arr.length; i++) 
{ 
    type var = arr[i];
    declarações da variável;
}

Se o array utilizado (no caso do exemplo a seguir, “meuArray”) for um número inteiro, ficaria assim com o uso de um loop for-each:

for (int count : meuArray){
<comando>
}

A partir do Java 8, é possível a utilização do método forEach() — o qual serve melhor para situações específicas, como veremos durante nosso guia:

list.forEach(meuArray -> meuArray.operação);

Para facilitar ainda mais seu entendimento, acompanhe, a seguir, o mesmo código sendo escrito com o laço for-each e, em seguida, usando o método forEach().

Usando o for-each loop clássico

import java.util.*;

public class ExemploForEach {

    public static void main(String[] args) {

        List<Integer> i = Arrays.asList(15, 11, 13, 9, 35);

        for(Integer item : i){
            System.out.print(item);
        }
    }
}

Usando o método forEach()

import java.util.*;

public class ExemploForEach {

    public static void main(String[] args) {

        List<Integer> itens = Arrays.asList(15, 11, 13, 9, 35);

    itens.forEach(System.out::println);
    }
}

Quais as vantagens e desvantagens do método Java forEach() em relação ao for-each loop na linguagem Java?

Os modelos de loop que levantamos durante este guia, o forEach clássico e o método forEach(), são usados para casos específicos, com cada um deles oferecendo uma vantagem ou desvantagem para determinada situação. Agora, abordaremos as principais delas.

Otimização de desempenho

Embora sejam raros os casos em que a troca do iterador forEach() pelo for-each convencional ofereça uma melhoria significativa no desempenho da aplicação, é algo a ser avaliado. Pacotes e bibliotecas usados em Java, certamente, terão algumas otimizações possíveis no quesito desempenho ao optarem por esse método.

Código mais sustentável e explícito durante a manutenção

Como vimos no exemplo acima, durante a apresentação das sintaxes utilizadas pelo forEach, o uso do método forEach() se torna bastante viável devido à facilitação dos processos de depuração do código. Ao mesmo tempo, simplificam também a adaptação e a extensibilidade da aplicação por outras pessoas desenvolvedoras.

Opção de suporte para execução paralela de recursos

O uso do iterador forEach() permite que o código tenha a possibilidade de ser otimizado — nos casos em que a implementação padrão do fluxo de dados não atenda aos requerimentos da aplicação desenvolvida. É possível que forneçamos nossa própria implementação, como configurações e preferências internas do sistema operacional — e sem prejudicar o código como um todo.

Como entender, em 5 exemplos de uso, o loop forEach?

Confira, a seguir, 5 exemplos que preparamos para ajudar você a compreender ainda mais sobre o uso do Java forEach loop. Tente reproduzi-los em sua máquina e lembre-se de deixar sua IDE ou compilador Java atualizado para a versão 8.

1. Como facilitamos a visualização do código usando o for-each loop

Repare que buscaremos por meio do nosso código filtrar os itens em determinada ArrayList. No exemplo, é possível perceber como podemos controlar a iteração dos elementos usando a estrutura do loop forEach:

import java.util.*;

public class forsimpleseforeach {
    
    public static void main(String[] args){
            List<Integer> itens = Arrays.asList(20, 100, 19, 555, 690, 518);

//utilizando o forEach:

    for(Integer item : itens){
        if (item == 100)
            System.out.println(item);
        }
    }
}

Nosso código pede que seja impresso na tela qualquer valor que seja igual a 100. Como ele faz parte do array que utilizamos, na posição 1, ele imprimirá 100 na tela. Se por acaso quisermos filtrar os números maiores do que 100 usando o mesmo método, fazemos da seguinte maneira:

import java.util.*;

public class forsimpleseforeach {

   public static void main(String[] args){
           List<Integer> itens = Arrays.asList(20, 100, 19, 555, 690, 518);
           
//utilizando o forEach:

   for(Integer item : itens){
       if (item > 100)
           System.out.println(item);
       }
   }
}

O resultado será o seguinte:

555
690
518

2. Exemplo de uso do forEach em Java: aplicativo que pede 2 números ao usuário e apresenta a soma entre eles

Nesse exemplo, vamos declarar o array e a variável ‘soma’ para somarmos os resultados oferecidos pelo usuário de nosso pequeno programa. Repare que usamos um laço for clássico para percorrermos nosso vetor.

Em seguida, precisamos percorrer todo o array e, como vimos, a melhor maneira de fazer isso é usando a estrutura de for-each loop. Nosso código ficará assim:

import java.util.*;

//utilizando um laço for simples:

public class forsimples {
    
    public static void main(String[] args){
            int[] num = new int[5];
            int soma =0;
            Scanner entrada1 = new Scanner(System.in);
            
            for(int cont=0 ; cont< num.length ; cont++){
                System.out.print("Digite um número"+(cont+1)+": ");
                num[cont]=entrada1.nextInt();
            }

//utilizando o foreach:

            for(int cont : num){
                soma += cont;
            }
            
            System.out.println("A soma dos dígitos é igual a "+soma);
        }
}

A saída é dependente dos inputs realizados pelo usuário — o qual será a soma dos números inseridos.

3. Iterando os nomes e imprimindo uma lista de convidados

Aqui, trazemos um exemplo bem simples, mas muito efetivo, para o uso dos loops forEach. Perceba que pedimos para o sistema que criamos imprimir um título para a lista e, em seguida, iterar os valores contidos no vetor “convidados”:

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

public class ExemploForEach {
  public static void main(String[] args) {
    String[] convidados = {"Maria", "Francisco", "Jair", "Benedita", "Joana", "Xavier"};

//iterando o Array com forEach:
    System.out.println("Os convidados para a festa são:");
    for(String festa : convidados) {
      System.out.println(festa);
    }
  }
}

A saída desse código será a seguinte:

Os convidados para a festa são:
Maria
Francisco
Jair
Benedita
Joana
Xavier

4. Escolhendo o maior valor entre várias pontuações em um jogo

Suponha que precisemos fazer um programa, o qual identifique o maior valor em determinado grupo de números para um jogo — o objetivo é mostrar qual foi a maior pontuação. No exemplo abaixo, você confere a utilização de um for-each loop para a avaliação de qual é o número maior em nosso ArrayList:

import java.util.ArrayList;

public class ForEachExemplo2   
{
    public static void main(String[] arg)
    {
        {
            int[] pontos = {32, 33, 2, 0, 110};
            int maior_pontuação = maximum(pontos);
            System.out.println("A pontuação maior do jogo é de " + maior_pontuação);
        }
    }
    public static int maximum(int[] num)
    {
        int numeromaximo = num[0];
         
// utilizando o forEach:

        for (int n : num)
        {
            if (n > numeromaximo)
            {
                numeromaximo = n;
            }
        }
    return numeromaximo;
    }
}

O retorno no terminal será o seguinte:

A pontuação maior do jogo é de 110

5. Simplificando a codificação da lista de convidados apresentada no exemplo 3

Com o uso do método forEach(), é possível simplificar muito ao codificarmos processos de iteração necessários em nossas aplicações. Veja, a seguir, um código que imprimirá a mesma saída do terceiro exemplo que utilizamos logo acima. Vale lembrar que esse método só funciona em compiladores atualizados a partir do Java 8.

import java.util.*;

public class ForEachExemplo3   
{
    public static void main(String[] arg)
    {
      List<String> convidados = new ArrayList<>(Arrays.asList("Maria", "Francisco", "Jair", "Benedita", "Joana", "Xavier"));
        System.out.println("Os convidados para a festa são:");
        convidados.forEach(nomes -> System.out.println(nomes));
        }
}

Quais as diferenças principais entre o for-each loop e o método forEach()?

Como já havíamos mostrado no começo de nosso guia, se buscarmos a explicação mais simples para esse tema, podemos entender que tanto o loop for quanto o ForEach loop têm a mesma funcionalidade — eles são responsáveis por iterar os elementos em dada coleção, como os ArrayLists, que abordamos durante nossos exemplos.

Se olharmos de maneira um pouco mais aprofundada para os dois, veremos que são iteradores diferentes e que se comportam de maneira bastante diversa entre si. Não é a toa que o forEach (ou for-each loop) também é chamado de enhanced loop. Basicamente, é uma estrutura de controle for um pouco mais avançada e mais limpa de ser implementada do que a convencional.

Podemos dizer que o for-each loop funciona como um iterador externo, enquanto o método forEach() — mais novo, lembrando que só pode ser implementado depois do Java 8 — funciona como um iterador interno. Mas por quê? Daremos detalhes sobre essas diferenças, mais adiante.

O loop for-each como um iterador externo

Ao trabalhar com iteradores externos, precisamos especificar para eles como as ações serão realizadas durante o processo. Isso acontece por conta de como a iteração é processada durante o loop. Dessa forma, o for-each loop alterna o “o quê” e “como” ele fará a iteração.

Considere o seguinte exemplo de loop:

for (String nome : nomes) {
    System.out.println(nome);
}

Embora não seja explícito às pessoas que programam esses loops, saiba que, por exemplo, os métodos next() e hasnext() — usados para invocar o próximo elemento da coleção e para saber se o loop chegou ao fim, respectivamente — não está exposto no código, mas é acessado durante a execução.

O método forEach() como iterador interno

Já quando falamos de um iterador interno, como o método forEach(), a própria coleção acessada é responsável por fazer a iteração — precisamos apenas dos comandos, para que contabilizem cada elemento da coleção em que trabalhamos.

O método forEach() é capaz de gerenciar a iteração em plano de fundo, permitindo à pessoa programadora apenas escrever as ações que devem ser realizadas nos elementos de determinada coleção, resumidamente.

Confira mais esse exemplo:

names.forEach(name -> System.out.println(name));

No método forEach() que usamos como exemplo logo acima, observamos que é utilizada uma declaração lambda — que é um pequeno bloco de código que recebe parâmetros e retorna valores. Isso quer dizer que apenas o próprio método precisa saber o que deve ser feito, passando toda a ação de iteração para a parte interna de processamento.

Concluindo, vimos que o Java forEach é um elemento que pode ser implementado a partir da versão do Java 8 e vem sendo atualizado desde então. Na maior parte das vezes, ele pode ser mais conveniente para a implementação do que o loop for convencional.

Também apresentamos o método forEach() e como realizar sua implementação a partir de exemplos simples para melhor absorção. Abordamos alguns detalhes sobre os tipos de implementações, em que esse método pode funcionar melhor do que as maneiras mais simples de iteração de elementos.

Deu para perceber como cada um deles trabalha e seu comportamento durante os processos na linguagem Java, certo? Por fim, mostramos as diferenças entre as ações realizadas pelo Java for-each loop e o método forEach().

Se você gostou deste guia e ainda quer aprender mais sobre Java e outras linguagens de programação, assine agora mesmo nossa newsletter! Receba de forma totalmente gratuita, em sua caixa de entrada, todas as novidades que preparamos no blog da Trybe!