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".
- 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
varno 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
forcomum. - (String
- O tipo de cada item. Tem que combinar com o tipo do array: array de
String, itemString. - 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
frutaemfrutas". - 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:
| Volta | fruta vale | Saí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 itens | o laço termina sozinho |
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 último | for-each |
| Somar, contar, achar o maior, procurar um item | for-each |
| Saber a posição de cada item (1º, 2º…) | for com índice |
| Mudar os valores do array | for com índice |
| Percorrer de trás para frente ou pulando itens | for com índice |
| Percorrer dois arrays juntos | for com índice |
| Remover itens de uma lista | removeIf ou Iterator (Nível 3) |
Quando dá errado
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.
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 :.
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
| Forma | Percorre |
|---|---|
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:
2. O tipo do item
Complete o tipo do item para percorrer double[] precos:
3. As letras
Complete para percorrer cada letra da String nome:
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
forcomum. - 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); useremoveIf.