Como funciona o for-each em Java: análise com exemplos do iniciante ao profissional

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: por que o for-each se tornou o "rei" dos loops em Java?

\n\n

Se você programou em Java por pelo menos uma semana, certamente já encontrou a construção for (Type var : collection). Essa sintaxe concisa é chamada de loop for-each (ou enhanced for loop). Ele surgiu no Java 5 (2004) e rapidamente se tornou o favorito dos desenvolvedores.

\n\n

Mas você sabe o que acontece por baixo dos panos quando a JVM encontra essa construção? Por que o for-each pode ser mais lento que o for comum para arrays? E por que ele às vezes lança ConcurrentModificationException, mesmo que você não esteja removendo nada?

\n\n

Neste artigo, vamos analisar como funciona o for-each em Java no nível do bytecode, compará-lo com loops clássicos e aprender a evitar armadilhas comuns. Vamos lá!

\n\n

Sintaxe e primeiros passos

\n\n

A sintaxe básica é a seguinte:

\n\n
for (TipoElemento variavel : colecao_ou_array) {\n    // corpo do loop\n}
\n\n

Exemplo com ArrayList:

\n\n
List<String> nomes = Arrays.asList("Ana", "Bruno", "Carlos");\n\nfor (String nome : nomes) {\n    System.out.println("Olá, " + nome + "!");\n}
\n\n

Saída:

\n\n
Olá, Ana!\nOlá, Bruno!\nOlá, Carlos!
\n\n

Simples, certo? Sim. Mas por trás dessa simplicidade, existem dois mecanismos completamente diferentes — para arrays e para coleções.

\n\n

Como o for-each funciona com arrays?

\n\n

Quando você escreve um for-each para um array, o compilador Java o transforma em um for comum com índice. Sem mágica.

\n\n

Seu código:

\n\n
int[] numeros = {10, 20, 30};\n\nfor (int num : numeros) {\n    System.out.println(num);\n}
\n\n

Após a compilação (descompile o bytecode — confira):

\n\n
int[] numeros = new int[]{10, 20, 30};\nfor (int i = 0; i < numeros.length; i++) {\n    int num = numeros[i];\n    System.out.println(num);\n}
\n\n

Conclusão importante: para arrays, o for-each e o for comum são equivalentes em desempenho. Sem custos adicionais com iteradores.

\n\n

Como o for-each funciona com coleções (List, Set)?

\n\n

Aqui é onde a coisa fica interessante. Para coleções, o for-each usa um iterador.

\n\n

Seu código:

\n\n
List<String> lista = new ArrayList<>();\nlista.add("Java");\nlista.add("Python");\nlista.add("C++");\n\nfor (String linguagem : lista) {\n    System.out.println(linguagem);\n}
\n\n

O compilador transforma isso em:

\n\n
List<String> lista = new ArrayList<>();\nlista.add("Java");\nlista.add("Python");\nlista.add("C++");\n\nfor (Iterator<String> it = lista.iterator(); it.hasNext(); ) {\n    String linguagem = it.next();\n    System.out.println(linguagem);\n}
\n\n

Ou seja:

\n
    \n
  • Chama-se lista.iterator() — obtém-se o iterador.
  • \n
  • Na condição — it.hasNext().
  • \n
  • No corpo — it.next().
  • \n
  • A variável linguagem é inicializada com o resultado de next().
  • \n
\n\n

O que isso significa na prática?

\n
    \n
  • Não é possível remover elementos dentro do for-each usando lista.remove() — você receberá um ConcurrentModificationException. Use it.remove() ou um for comum.
  • \n
  • Não é possível modificar a coleção (adicionar/remover) durante a iteração — o mesmo erro.
  • \n
  • Desempenho: para ArrayList, a diferença para o for comum é mínima (criação do objeto iterador). Para LinkedList — o for-each é muito mais rápido que for (int i = 0; i < lista.size(); i++), porque get(i) em LinkedList é O(n) a cada chamada!
  • \n
\n\n

E quanto ao Map? Iteração por pares chave-valor

\n\n

Map não implementa Iterable diretamente, portanto o for-each

Blogs

Book Recommendations