Como utilizar For-Each Loop em Java
- #Java
Para que serve o For-Each Loop em Java ?
O for-each é uma estrutura de iteração para navegar pelos elementos de uma coleção (ou seja, pode ser listas, mapas e conjuntos) ou array de forma mais fácil e sintaticamente mais simples. Antes de apresentá-lo, vamos entender um pouco de como eram feitas iterações anteriormente para compreender um pouco das evoluções do Java e ter uma visão abrangente da feature.
Vamos inicialmente usar como exemplo uma lista de letras do alfabeto criando um ArrayList. Se quiser utilizar uma IDE para ir copiando e testando o código, pode te ajudar bastante a memorizar!
List<String> letras = new ArrayList<>();
letras.add("A");
letras.add("B");
letras.add("C");
letras.add("D");
Era "pré For-Each"
Algum tempo atrás, especificamente na versão 4, em Java não era possível iterar uma coleção com tanta facilidade como atualmente. Era necessário utilizar a interface Iterator para ir navegando nos elementos.
for(Iterator<String> i = letras.iterator(); i.hasNext();){
System.out.println(i.next());
}
A interface Iterator obtida pelo método iterator() chamado no "for" permitia montar um loop e ir navegando item a item na lista.
Outra forma seria utilizar referência de índices na lista.
for(int i = 0; i < letras.size(); i++){
System.out.println(letras.get(i));
}
Dessa forma declaramos "i" como 0 (zero), valor do qual todo índice de um ArrayList começa. Fazemos a iteração até o tamanho do array e incrementamos a variável "i" a cada execução. Dessa forma, conseguimos o mesmo resultado que é apresentar os elementos.
E por fim, também era possível utilizando a estrutura "while".
int indice = 0;
while (letras.size() > indice) {
System.out.println(letras.get(indice++));
}
Dessa forma, enquanto o tamanho da lista for maior que o índice a execução acontecerá. Também temos o mesmo resultado das alternativas anteriores :)
For-Each Loop lançado
Com o lançamento da versão 5 do Java, o For-Each Loop facilitou muito essa operação deixando de ser necessário utilizar Iterator, while ou até loop com índices.
for(String letra : letras){
System.out.println(letra);
}
Como você pode ver, é mais simples e legível e menos verboso. Pode-se ler a estrutura até com maior facilidade, por exemplo: "para cada letra em letras, imprima no console".
Também é possível usar For-Each com arrays.
int[] numeros = new int[]{1, 2, 3, 4, 5};
for(int numero : numeros){
System.out.println(numero);
}
Como já comentamos anteriormente, com a estrutura Set também é possível utilizar For-Each.
Set<String> outrasLetras = new HashSet<>();
outrasLetras.add("J");
outrasLetras.add("Y");
outrasLetras.add("B");
outrasLetras.add("a");
outrasLetras.add("c");
for(String outraLetra : outrasLetras) {
System.out.println(outraLetra);
}
Saída:
a
B
c
Y
J
Um ponto importante de ressaltar cuidado é que utilizar Set com a implementação de HashSet não garante ordem. Conforme pode ser visto na documentação:
This class implements theSet
interface, backed by a hash table (actually aHashMap
instance). It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time. This class permits thenull
element.
Traduzindo:
Esta classe implementa a interface Set, apoiada por uma tabela de hash (na verdade, uma instância de HashMap). Não dá garantias quanto à ordem de iteração do conjunto; em particular, não garante que a ordem se mantenha constante ao longo do tempo. Esta classe permite o elemento nulo.
Assim, qualquer ordem pode ser obtida ao executar utilizando HashSet.
Portanto, é seguro dizer que é possível obter ordem de inserção a partir de arrays, ArrayList mas não de HashSet. Nesse caso, considere utilizar LinkedHashSet.
Set<String> outrasLetras = new LinkedHashSet<>();
outrasLetras.add("J");
outrasLetras.add("Y");
outrasLetras.add("B");
outrasLetras.add("a");
outrasLetras.add("c");
for(String outraLetra : outrasLetras) {
System.out.println(outraLetra);
}
Saída:
J
Y
B
a
c
Com TreeSet conseguimos ordenação natural:
Set<String> outrasLetras = new TreeSet<>();
outrasLetras.add("J");
outrasLetras.add("Y");
outrasLetras.add("B");
outrasLetras.add("a");
outrasLetras.add("c");
for(String outraLetra : outrasLetras) {
System.out.println(outraLetra);
}
}
Saída:
B
J
Y
a
c
Nesse caso, primeiro acontece a ordenação para letras maiúsculas e depois minúsculas.
Por fim, é possível utilizar For-Each para iterar sobre Mapas.
Map<String, Integer> notasPorAluno = new HashMap<>();
notasPorAluno.put("João", 10);
notasPorAluno.put("Jéssica", 6);
notasPorAluno.put("Lucas", 6);
notasPorAluno.put("Andressa", 10);
for(Map.Entry<String, Integer> entradaDoMapa : notasPorAluno.entrySet()){
System.out.println("Aluno: " + entradaDoMapa.getKey() + " - Nota:" + entradaDoMapa.getValue());
}
Saída:
Aluno: João- Nota:10
Aluno: Andressa- Nota:10
Aluno: Jéssica- Nota:6
Aluno: Lucas- Nota:6
Como Map é uma estrutura com entradas com chave e valor, o for-each fica um pouco diferente nesse cenário :)
Vale salientar que a questão de ordenação segue o mesmo padrão de Set: HashMap não garante ordem, LinkedHashMap garante ordem de inserção e TreeMap segue ordenação natural com base na chave.
For-Each na Stream API
Com o lançamento do Java 8 e da Stream API e a possibilidade de programação funcional em Java, foi possível deixar a sintaxe mais enxuta ainda com a operação forEach da API.
List<String> letras = new ArrayList<>();
letras.add("A");
letras.add("B");
letras.add("C");
letras.add("D");
letras.stream().forEach(System.out::println);
Como pode ser visto, utilizando os método da Stream API a sintaxe diminui drasticamente.
E aí, conseguiu aprender um pouco mais sobre For-Each ?
Espero ter contribuído com seu aprendizado!
Referências:
- https://www.baeldung.com/java-for-each-loop
- https://docs.oracle.com/javase/8/docs/technotes/guides/language/foreach.html
- https://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html