Menu

Loop for-each em Java: sintaxe, exemplos e pegadinhas

O loop for-each do Java (for melhorado) explicado: iteração limpa sobre arrays e coleções, quando usá-lo e a pegadinha da modificação que confunde todo mundo.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Quando o índice só atrapalha

Um loop for com contador dá a você um contador, uma condição e um passo de atualização. Mas em grande parte do tempo você não se importa de verdade com a posição de um elemento: você só quer fazer algo com cada um, em ordem, do início ao fim. Gerenciar um índice para isso é trabalho à toa, e é exatamente onde os erros de off-by-one se infiltram.

O loop for-each (o nome que o Java dá a ele é for melhorado) elimina o contador por completo. Você nomeia uma variável, aponta-a para uma coleção e o loop entrega cada elemento por vez.

Sintaxe básica

A forma é for (Tipo elemento : colecao). Leia os dois-pontos como a palavra "em":

Não há i, nem scores.length, nem scores[i]. A cada passagem, score é o próximo elemento. O loop roda uma vez por elemento e para automaticamente quando não há mais nenhum: você não pode passar do fim nem começar um elemento cedo demais.

Percorrendo uma lista

O mesmo loop funciona com qualquer coisa iterável, o que inclui List, Set e os outros tipos de coleção. O tipo do elemento vem antes do nome da variável:

Repare que você não precisou saber nem se importar se langs é apoiada por um array, uma lista encadeada ou qualquer outra coisa: o for-each funciona igual em todas elas. Essa é a sua verdadeira força: uma sintaxe legível para toda coleção.

var poupa você de escrever o nome do tipo

Se o tipo do elemento for longo ou óbvio, var deixa o compilador inferi-lo para você não se repetir:

Sem var, essa variável do loop seria o trava-língua Map.Entry<String, Integer>. var mantém tudo legível, e o tipo continua totalmente verificado em tempo de compilação: não é um tipo solto e dinâmico.

A pegadinha da modificação

Aqui está a regra que confunde todo mundo: você não pode adicionar nem remover de uma coleção enquanto um loop for-each a percorre. Fazer isso lança uma ConcurrentModificationException:

List<String> items = new ArrayList<>(List.of("a", "b", "c"));

for (String item : items) {
    if (item.equals("b")) {
        items.remove(item);   // lança ConcurrentModificationException
    }
}

O loop percebe que a lista mudou por baixo dele e interrompe a execução em vez de pular ou repetir elementos silenciosamente. Para remover com segurança, desça para um Iterator explícito, que tem um remove() que o loop conhece:

Um atalho comum é items.removeIf(item -> item.equals("b")), que faz a mesma coisa em uma única linha.

Apenas leitura, sem reatribuir

Outra limitação sutil: atribuir à variável do loop muda apenas a cópia local, não a coleção. Isso surpreende quem vem de linguagens em que a variável do loop é uma referência viva:

Se você precisa escrever de volta no array, precisa do índice, e isso significa o clássico loop for com contador: for (int i = 0; i < nums.length; i++) nums[i] = nums[i] * 10;. Para elementos que são objetos, você pode alterar o objeto para o qual a variável aponta (chamando um setter, por exemplo), mas não pode substituí-lo na coleção.

break e continue continuam funcionando

Um for-each é um loop de verdade, então break e continue se comportam exatamente como em qualquer outro lugar: break sai do loop, continue pula para o próximo elemento:

Isso imprime keep e depois keep: ele pula "skip" e para em "stop" antes de chegar a "never". Então você não é obrigado a visitar todos os elementos; você apenas abre mão do índice em troca de um código mais limpo.

Próximo: Arrays

Você já percorreu arrays algumas vezes sem se deter no que eles realmente são: contêineres indexados de tamanho fixo com aquele campo .length. A próxima página volta ao início e cobre os arrays como deve ser: como declará-los, os valores padrão com que eles começam e como o seu tamanho fixo se diferencia de um ArrayList que pode crescer.

Perguntas frequentes

O que é um loop for-each em Java?

Um loop for-each (também chamado de for melhorado) percorre todos os elementos de um array ou coleção sem um contador: for (Tipo item : colecao) { ... }. Leia como "para cada item da coleção". Ele é mais limpo do que um loop for com contador quando você só precisa de cada elemento e nunca do índice.

Qual é a diferença entre um loop for e um loop for-each em Java?

O loop for clássico usa um contador explícito (for (int i = 0; i < arr.length; i++)), então você controla o índice e a direção. O loop for-each, for (Tipo x : arr), não tem índice: ele visita todos os elementos em ordem. Use o for-each para passagens de leitura, do início ao fim; use o loop com contador quando precisar do índice, quiser pular elementos ou modificar a estrutura da coleção.

Por que meu loop for-each lança ConcurrentModificationException?

Porque você chamou add() ou remove() na coleção enquanto a percorria com um for-each. O loop detecta a mudança estrutural e lança a exceção para proteger você de comportamento indefinido. Para remover elementos com segurança, use um Iterator explícito e o método remove() dele, ou junte os itens a apagar e remova-os depois do loop.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR