Em Java, o loop for-each simplifica o processo de passagem de qualquer coleção ou array, mas nem todo programador Java conhece alguns dos detalhes do loop for-each que será descrito neste artigo. Ao contrário de outros termos lançados no Java 5: genéricos lançados por alias, encapsulamento automático e parâmetros variados, os desenvolvedores Java usam loops for-each com mais frequência do que qualquer outro recurso, mas quando questionados sobre como funcionam os loops for-each avançados, ou quais são os recursos básicos requisitos ao usar uma coleção em um loop for-each, nem todos podem respondê-la.
Este tutorial e exemplo visa preencher essa lacuna investigando alguns quebra-cabeças interessantes em loops for-each. Ok, não vamos entrar em detalhes, vamos dar uma olhada em nosso primeiro problema com o loop for-each do Java5.
Pergunta de loop avançado 1
Considere o código a seguir que percorre um agregador ou classe de coleção definido pelo usuário. O que esse código imprimirá, se ele gera uma exceção ou um erro do compilador:
Copie o código do código da seguinte forma:
teste de pacote;
/**
* Classe Java para mostrar como funciona o loop for-each em Java
*/
classe pública ForEachTest {
public static void main(String args[]){
CustomCollection<String> minhaColeção = new CustomCollection<String>();
minhaColeção.add("Java");
minhaColeção.add("Scala");
myCollection.add("Groovy");
//O que esse código fará, imprimir linguagem, lançar exceção ou erro em tempo de compilação
for(linguagem da string: minhaColeção){
System.out.println(idioma);
}
}
}
Abaixo está nossa classe CustomCollection, que é uma classe genérica que, como qualquer outra classe Collection, depende de um ArrayList e fornece métodos para adicionar e remover itens da Coleção.
Copie o código do código da seguinte forma:
teste de pacote;
classe pública CustomCollection<T>{
intervalo privado ArrayList<T>;
public CustomCollection(){
bucket = new ArrayList();
}
public int tamanho() {
retornar bucket.size();
}
public boolean isEmpty() {
return bucket.isEmpty();
}
público booleano contém(T o) {
retornar bucket.contains(o);
}
adição booleana pública (T e) {
retornar bucket.add(e);
}
public boolean remove(T o) {
retornar bucket.remove(o);
}
}
Responder:
O código acima não será compilado porque nossa classe CustomCollection não implementa a interface java.lang.Iterable. O erro em tempo de compilação é o seguinte:
Copie o código do código da seguinte forma:
Exceção no thread "principal" java.lang.RuntimeException: Código fonte não compilável - for-each não aplicável ao tipo de expressão
obrigatório: array ou java.lang.Iterable
encontrado: test.CustomCollection
em test.ForEachTest.main(ForEachTest.java:24)
Um fato interessante para aprender com isso é que o loop for-each se aplica apenas ao array Java e às classes Collection que implementam a interface Iterable, e como todas as classes Collection integradas implementam a interface java.util.Collection e herdaram Iterable, isso Um detalhe que muitas vezes é esquecido pode ser visto na declaração de tipo da interface Collection "public interface Collection estende Iterable". Portanto, para resolver o problema acima, você pode simplesmente deixar CustomCollection implementar a interface Collection ou herdar AbstractCollection, que é a implementação universal padrão e mostra como usar classes e interfaces abstratas ao mesmo tempo para melhor flexibilidade. Agora vamos dar uma olhada no segundo quebra-cabeça do loop for-each:
A segunda dificuldade com loops Java for-each:
O exemplo de código a seguir lançará uma ConcurrentModificationException. Aqui usamos o iterador padrão e o loop for-each para iterar pelo ArrayList e, em seguida, excluir os elementos. Você precisa descobrir qual parte do código lançará ConcurrentModificationException e por quê? Observe que a resposta pode ser ambas, nenhuma, ou uma ou outra.
Copie o código do código da seguinte forma:
teste de pacote;
importar java.util.ArrayList;
importar java.util.Collection;
importar java.util.Iterator;
/**
* Classe Java para demonstrar o funcionamento interno do loop for-each em Java
* @autor Javin Paul
**/
classe pública ForEachTest2 {
public static void main(String args[]){
Coleção<String> lista = new ArrayList<String>();
lista.add("Android");
lista.add("iPhone");
list.add("Windows Mobile");
// Qual código lançará ConcurrentModificationException, ambos,
// nenhum ou um deles
//exemplo 1
Iterador<String> itr = list.iterator();
enquanto(itr.hasNext()){
String lang = itr.next();
lista.remove(lang);
}
//exemplo 2
for(linguagem da string: lista){
lista.remove(idioma);
}
}
}
Cerca de 70% dos desenvolvedores Java dirão que o primeiro bloco de código lançará uma exceção ConcurrentModificationException porque não usamos o método remove do iterador para excluir elementos, mas usamos o método remove() de ArrayList. No entanto, poucos desenvolvedores Java diriam que o mesmo problema ocorre com o loop for-each, pois não estamos usando o iterador aqui. Na verdade, o segundo trecho de código também lança uma ConcurrentModificationException, que se torna óbvia após resolver a primeira confusão. Como o loop for-each usa um Iterator internamente para percorrer a Coleção, ele também chama Iterator.next(), que verifica alterações (de elementos) e lança uma ConcurrentModificationException. Você pode ver isso na saída abaixo, obtida ao executar o segundo trecho após comentar o primeiro trecho.
Copie o código do código da seguinte forma:
Exceção no thread "principal" java.util.ConcurrentModificationException
em java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
em java.util.AbstractList$Itr.next(AbstractList.java:343)
em test.ForEachTest2.main(ForEachTest2.java:34)
Isso é tudo sobre o loop for-each do Java5. Vimos muitos problemas que os programadores Java enfrentam ao escrever código para iterar em uma classe Collection, especialmente ao iterar em uma coleção enquanto excluem elementos ao mesmo tempo. Lembre-se de sempre usar o método remove do Iterator ao remover objetos de qualquer Coleção (como um Mapa, Conjunto ou Lista). Lembre-se também de que o loop for-each é apenas açúcar sintático (açúcar sintático) além do uso padrão do método. código Iterador padrão) apenas.
Nota do tradutor: Açúcar sintático, também traduzido como gramática revestida de açúcar, é um termo inventado pelo cientista da computação britânico Peter J. Landin, que se refere a um certo tipo de gramática adicionada às linguagens de computador. linguagem, mas facilita o uso dos programadores. De modo geral, o uso do açúcar de sintaxe pode aumentar a legibilidade do programa, reduzindo assim a chance de erros no código do programa.