Java for-each

Muitas vezes você não quer "contar de 1 a 10": quer passar por cada item de um grupo de valores, como cada fruta da lista de compras ou cada nota da turma. Para isso o Java tem uma forma mais curta do for, o for-each ("para cada"). Nele não há contador, nem condição, nem passo: só "para cada item deste grupo, faça isto".

Você vai aprender
  • O que é um array, o suficiente para usá-lo num laço.
  • A anatomia do for-each: for (tipo item : grupo).
  • Percorrer arrays, listas e as letras de um texto; somar e contar com ele.
  • Quando o for-each não serve: quando você precisa da posição, quer mudar os valores ou remover itens.
  • Como usar var no for-each.

Os exemplos rodam no terminal da Ana (máquina fictícia notebook, pasta ~/java, JDK 25) com java Main.java.


A ideia antes do código

A Ana chega do mercado com uma sacola e vai guardando as compras: tira um item, guarda; tira o próximo, guarda; até a sacola ficar vazia. Ela não numera os itens nem conta quantos são. Só pensa: para cada item da sacola, guarde-o.

O for-each é essa sacola. Você entrega a ele um grupo de valores e ele te dá um item por vez, do primeiro ao último, sem você precisar saber quantos são nem em que posição cada um está.

Um array em 30 segundos

Para ter um "grupo de valores", vamos usar um array: uma variável que guarda vários valores do mesmo tipo, um atrás do outro. Ele tem uma aula inteira, Arrays, logo depois deste bloco. Por enquanto basta isto:

String[] frutas = {"maçã", "banana", "uva", "laranja"};
String[]
O tipo: "vários String". Os colchetes [] dizem que é um array.
frutas
O nome da variável.
= {…};
Os valores, entre chaves, separados por vírgula. Aqui são 4.

O primeiro for-each

public class Main {
    public static void main(String[] args) {
        String[] frutas = {"maçã", "banana", "uva", "laranja"};
        for (String fruta : frutas) {
            System.out.println("Eu gosto de " + fruta);
        }
    }
}
$ java Main.java
Eu gosto de maçã
Eu gosto de banana
Eu gosto de uva
Eu gosto de laranja

Anatomia do for-each

for
A mesma palavra-chave do for comum.
(String
O tipo de cada item. Tem que combinar com o tipo do array: array de String, item String.
fruta
O nome que você escolhe para o item da vez. A cada volta, ele recebe o próximo valor.
:
Os dois-pontos. Leia como "em": "para cada fruta em frutas".
frutas)
O grupo a percorrer: um array ou uma lista.
{ … }
O corpo, que roda uma vez para cada item.

A tabela mostra o que a variável fruta vale em cada volta:

Voltafruta valeSaída
1ª"maçã"Eu gosto de maçã
2ª"banana"Eu gosto de banana
3ª"uva"Eu gosto de uva
4ª"laranja"Eu gosto de laranja
—acabaram os itenso laço termina sozinho
Dica de nome

Use o plural para o grupo e o singular para o item: frutas / fruta, notas / nota, alunos / aluno. O laço fica legível como uma frase: "para cada nota em notas".

O mesmo laço com o for comum

Antes do for-each existir (ele chegou no Java 5, em 2004), percorrer um array era assim:

public class Main {
    public static void main(String[] args) {
        String[] frutas = {"maçã", "banana", "uva", "laranja"};
        for (int i = 0; i < frutas.length; i++) {
            System.out.println("Eu gosto de " + frutas[i]);
        }
    }
}
$ java Main.java
Eu gosto de maçã
Eu gosto de banana
Eu gosto de uva
Eu gosto de laranja

A saída é idêntica. Mas repare em quanta coisa a mais: o contador i começando em 0, o frutas.length (o tamanho do array), o frutas[i] (o item na posição i). Tudo isso é explicado em Arrays e Percorrer Arrays. No for-each, o Java faz esse trabalho por você, e não há como errar o início ou o limite. Por isso o nome oficial dele é for aprimorado (enhanced for).


Somar e contar com o for-each

Os padrões do for funcionam igualzinho: um acumulador criado antes do laço e atualizado dentro.

Somar e tirar a média

public class Main {
    public static void main(String[] args) {
        double[] notas = {7.5, 8.0, 6.5, 9.0};
        double soma = 0;
        for (double nota : notas) {
            soma += nota;
        }
        System.out.println("Soma: " + soma);
        System.out.println("Média: " + soma / notas.length);
    }
}
$ java Main.java
Soma: 31.0
Média: 7.75

O array agora é de double (números com vírgula), então o item também é double. O notas.length é a quantidade de notas (4), usada para a média.

Contar quem passa num teste

Quantas pessoas desta lista de idades são maiores de idade? Um contador que só sobe quando o if deixa:

public class Main {
    public static void main(String[] args) {
        int[] idades = {12, 17, 25, 30, 15, 42};
        int maiores = 0;
        for (int idade : idades) {
            if (idade >= 18) {
                maiores++;
            }
        }
        System.out.println("Maiores de idade: " + maiores);
    }
}
$ java Main.java
Maiores de idade: 3

Missão: a Ana comprou itens de R$ 12, R$ 5, R$ 30 e R$ 8. Complete o for-each para somar os preços e mostrar Total da compra: R$ 55.

public class Main {
    public static void main(String[] args) {
        int[] precos = {12, 5, 30, 8};
        int total = 0;
        // escreva o for-each aqui

        System.out.println("Total da compra: R$ " + total);
    }
}
public class Main {
    public static void main(String[] args) {
        int[] precos = {12, 5, 30, 8};
        int total = 0;
        for (int preco : precos) {
            total += preco;
        }
        System.out.println("Total da compra: R$ " + total);
    }
}

Não é só para arrays

Listas

O for-each percorre qualquer coleção do Java, como as listas. Uma lista é parecida com um array, mas pode crescer e diminuir; você vai conhecê-las em ArrayList, no Nível 3. Aqui usamos List.of, que cria uma lista pronta (o <String> diz que é uma lista de textos):

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> alunos = List.of("Ana", "Bruno", "Carla");
        for (String aluno : alunos) {
            System.out.println("Bom dia, " + aluno + "!");
        }
    }
}
$ java Main.java
Bom dia, Ana!
Bom dia, Bruno!
Bom dia, Carla!

O laço é escrito exatamente igual ao do array. Essa é uma das vantagens do for-each: se um dia você trocar o array por uma lista, o laço não muda.

As letras de um texto

Uma String não pode ir direto no for-each, mas o método toCharArray() transforma o texto num array de char (uma letra por posição, veja Métodos de String):

public class Main {
    public static void main(String[] args) {
        String palavra = "Java";
        for (char letra : palavra.toCharArray()) {
            System.out.println(letra);
        }
    }
}
$ java Main.java
J
a
v
a

var no for-each

Em vez de escrever o tipo do item, você pode usar var e deixar o Java descobrir pelo tipo do grupo (veja var). Java 10+

public class Main {
    public static void main(String[] args) {
        String[] frutas = {"maçã", "banana", "uva"};
        for (var fruta : frutas) {
            System.out.println(fruta.toUpperCase());
        }
    }
}
$ java Main.java
MAÇÃ
BANANA
UVA

Como frutas é um String[], o Java sabe que cada fruta é uma String, e por isso o toUpperCase() (passar para maiúsculas) funciona. O var ajuda quando o tipo é comprido, como Map.Entry<String, Integer>, que você verá em HashMap. Com tipos curtos como String e int, escrever o tipo deixa o código mais claro para quem está aprendendo. Em Java 8 ou anterior, var não existe: escreva o tipo.


Quando o for-each não serve

O for-each é simples justamente porque esconde a posição de cada item. Isso cobra um preço em três situações.

1. Você precisa da posição (o índice)

No pódio de uma corrida, a posição é a informação. O for-each não sabe se o item é o primeiro ou o terceiro; o for com contador sabe:

public class Main {
    public static void main(String[] args) {
        String[] podio = {"Ana", "Bruno", "Carla"};
        for (int i = 0; i < podio.length; i++) {
            System.out.println((i + 1) + "º lugar: " + podio[i]);
        }
    }
}
$ java Main.java
1º lugar: Ana
2º lugar: Bruno
3º lugar: Carla

O mesmo vale para percorrer de trás para frente, pular itens (de 2 em 2) ou comparar dois arrays ao mesmo tempo (o item 0 de um com o item 0 do outro): tudo isso precisa do índice, então use o for comum.

2. Você quer mudar os valores do array

A professora decidiu dar 1 ponto a mais para todos. Parece fácil com for-each…

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] notas = {6, 7, 8};
        for (int nota : notas) {
            nota = nota + 1;
        }
        System.out.println(Arrays.toString(notas));
    }
}
$ java Main.java
[6, 7, 8]                    « nada mudou!

(Arrays.toString mostra o array inteiro entre colchetes; veja A Classe Arrays.) Compilou, rodou, não deu erro… e as notas continuam as mesmas. Por quê? A variável nota é uma cópia do valor da vez, como um papel onde o Java anotou "6". Você somou 1 no papel, mas o array não ficou sabendo. Para mudar o array, é preciso escrever na posição dele, e para isso, de novo, você precisa do índice:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] notas = {6, 7, 8};
        for (int i = 0; i < notas.length; i++) {
            notas[i] = notas[i] + 1;
        }
        System.out.println(Arrays.toString(notas));
    }
}
$ java Main.java
[7, 8, 9]

3. Você quer remover itens de uma lista

Com uma lista que pode mudar de tamanho (ArrayList), remover um item durante o for-each estraga o laço. A Ana quer tirar a maçã da lista de frutas:

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

public class Main {
    public static void main(String[] args) {
        List<String> frutas = new ArrayList<>(List.of("maçã", "banana", "uva"));
        for (String fruta : frutas) {
            if (fruta.equals("maçã")) {
                frutas.remove(fruta);
            }
        }
        System.out.println(frutas);
    }
}
$ java Main.java
Exception in thread "main" java.util.ConcurrentModificationException
	at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1096)
	at java.base/java.util.ArrayList$Itr.next(ArrayList.java:1050)
	at Main.main(Main.java:7)

ConcurrentModificationException quer dizer "modificação simultânea": a lista mudou enquanto estava sendo percorrida. A última linha, at Main.main(Main.java:7), aponta para a linha do for, onde o laço tentou pegar o próximo item e percebeu a mudança. (As linhas com java.base são o código do próprio Java, por dentro da lista. Você vai aprender a ler esse "rastro" em O que são Exceções.)

Pior: com outro item, o erro pode nem aparecer. Trocando "maçã" por "banana" (o penúltimo), o mesmo programa mostra [maçã, uva] sem reclamar, por pura coincidência de como a lista funciona por dentro. Não confie: nunca remova itens de uma coleção dentro do for-each dela. O jeito certo é o removeIf (que usa uma lambda) ou um Iterator, ambos do Nível 3:

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

public class Main {
    public static void main(String[] args) {
        List<String> frutas = new ArrayList<>(List.of("maçã", "banana", "uva"));
        frutas.removeIf(fruta -> fruta.equals("maçã"));
        System.out.println(frutas);
    }
}
$ java Main.java
[banana, uva]

Qual usar

Você quer…Use
Ler cada item, do primeiro ao últimofor-each
Somar, contar, achar o maior, procurar um itemfor-each
Saber a posição de cada item (1º, 2º…)for com índice
Mudar os valores do arrayfor com índice
Percorrer de trás para frente ou pulando itensfor com índice
Percorrer dois arrays juntosfor com índice
Remover itens de uma listaremoveIf ou Iterator (Nível 3)

Quando dá errado

"incompatible types: String cannot be converted to int"
public class Main {
    public static void main(String[] args) {
        String[] frutas = {"maçã", "banana", "uva"};
        for (int fruta : frutas) {
            System.out.println(fruta);
        }
    }
}
$ java Main.java
Main.java:4: error: incompatible types: String cannot be converted to int
        for (int fruta : frutas) {
                         ^
1 error
error: compilation failed

O que quer dizer: "tipos incompatíveis: String não pode ser convertida em int". O array é de String, mas a variável do item foi declarada int. O ^ aponta para o grupo, de onde vêm os itens do tipo errado.

Como consertar: use o mesmo tipo do array (String fruta) ou var fruta.

"for-each not applicable to expression type"
public class Main {
    public static void main(String[] args) {
        int total = 10;
        for (int n : total) {
            System.out.println(n);
        }
    }
}
$ java Main.java
Main.java:4: error: for-each not applicable to expression type
        for (int n : total) {
                     ^
  required: array or java.lang.Iterable
  found:    int
1 error
error: compilation failed

O que quer dizer: "o for-each não se aplica a este tipo". Depois dos dois-pontos tem que vir um grupo: required: array or java.lang.Iterable ("é preciso um array ou algo percorrível", como uma lista). Veio um int, um número só (found: int). Quem vem do Python costuma tentar "percorrer o número 10". Uma String direta também dá esse erro: use texto.toCharArray().

Como consertar: para repetir 10 vezes, use o for com contador: for (int n = 1; n <= total; n++).

in no lugar dos dois-pontos
public class Main {
    public static void main(String[] args) {
        String[] frutas = {"maçã", "banana", "uva"};
        for (String fruta in frutas) {
            System.out.println(fruta);
        }
    }
}
$ java Main.java
Main.java:4: error: ';' expected
        for (String fruta in frutas) {
                         ^
Main.java:4: error: ';' expected
        for (String fruta in frutas) {
                            ^
Main.java:4: error: not a statement
        for (String fruta in frutas) {
                             ^
3 errors
error: compilation failed

O que quer dizer: outras linguagens (Python, JavaScript) escrevem "for fruta in frutas". Em Java, in não é palavra-chave; o javac não entende a linha e tenta adivinhar que faltam ;. Três erros, uma causa só.

Como consertar: troque in por :.

Usar o item depois do laço: "cannot find symbol"
public class Main {
    public static void main(String[] args) {
        String[] frutas = {"maçã", "banana", "uva"};
        for (String fruta : frutas) {
            System.out.println(fruta);
        }
        System.out.println(fruta);
    }
}
$ java Main.java
Main.java:7: error: cannot find symbol
        System.out.println(fruta);
                           ^
  symbol:   variable fruta
  location: class Main
1 error
error: compilation failed

O que quer dizer: como no for comum, a variável do item só existe dentro do laço (veja o escopo em for). Se você quer guardar um item para depois (o último, o maior…), crie uma variável antes do laço e copie o valor para ela lá dentro.


Referência

FormaPercorre
for (String f : frutas)Cada item de um String[]
for (int n : numeros)Cada item de um int[]
for (double nota : notas)Cada item de um double[]
for (String a : lista)Cada item de uma List<String>
for (char c : texto.toCharArray())Cada letra de uma String
for (var item : grupo)Qualquer um deles, com o tipo deduzido Java 10+

Exercícios

1. Complete o for-each

Complete para percorrer o array String[] cores:

for (String cor cores)

2. O tipo do item

Complete o tipo do item para percorrer double[] precos:

for ( preco : precos)

3. As letras

Complete para percorrer cada letra da String nome:

for (char c : )

4. Depois de int[] v = {1, 2, 3}; for (int x : v) { x = x * 10; }, quanto vale o array v?

5. Você quer mostrar "Aluno 1: Ana", "Aluno 2: Bruno"… Qual laço é o mais adequado?

6. O que o for-each não aceita depois dos dois-pontos?

Missão final: conte quantas frutas do array têm mais de 4 letras e mostre Frutas com mais de 4 letras: seguido do número. Use um for-each e o método length() da String (por exemplo, "uva".length() vale 3).

public class Main {
    public static void main(String[] args) {
        String[] frutas = {"uva", "banana", "kiwi", "laranja", "pera", "manga"};
        int quantas = 0;
        // escreva o for-each aqui

        System.out.println("Frutas com mais de 4 letras: " + quantas);
    }
}
public class Main {
    public static void main(String[] args) {
        String[] frutas = {"uva", "banana", "kiwi", "laranja", "pera", "manga"};
        int quantas = 0;
        for (String fruta : frutas) {
            if (fruta.length() > 4) {
                quantas++;
            }
        }
        System.out.println("Frutas com mais de 4 letras: " + quantas);
    }
}

Resumo

  • for (Tipo item : grupo) { … } roda o corpo uma vez para cada item, do primeiro ao último. Leia o : como "em".
  • Funciona com arrays, listas e qualquer coleção; para as letras de um texto, use texto.toCharArray().
  • O tipo do item precisa combinar com o do grupo, ou use var (Java 10+).
  • Não há índice: para saber a posição, percorrer ao contrário ou pular itens, use o for comum.
  • A variável do item é uma cópia: mudar ela não muda o array.
  • Nunca remova itens de uma lista dentro do for-each dela (ConcurrentModificationException); use removeIf.