Qual é, se houver, a diferença de desempenho entre os dois loops a seguir?
for (Object o: objectArrayList) {
o.DoSomething();
}
e
for (int i=0; i<objectArrayList.size(); i++) {
objectArrayList.get(i).DoSomething();
}
java
performance
for-loop
eflles
fonte
fonte
Respostas:
Do item 46 em Java efetivo de Joshua Bloch:
fonte
Todos esses loops fazem exatamente o mesmo, eu só quero mostrá-los antes de jogar meus dois centavos.
Primeiro, a maneira clássica de percorrer a Lista:
Segundo, a maneira preferida, pois é menos suscetível a erros (quantas vezes você fez o "oops, misturou as variáveis iej nesses loops dentro dos loops")?).
Terceiro, o micro-otimizado para loop:
Agora, os dois centavos reais: pelo menos quando eu estava testando, o terceiro foi o mais rápido ao contar milissegundos em quanto tempo levou para cada tipo de loop com uma operação simples repetida alguns milhões de vezes - isso estava usando o Java 5 com jre1.6u10 no Windows, caso alguém esteja interessado.
Embora pelo menos pareça ser o terceiro mais rápido, você realmente deve se perguntar se deseja correr o risco de implementar essa otimização do olho mágico em todo o código do loop, pelo que eu vi, o loop real não é ' Geralmente, é a parte mais demorada de qualquer programa real (ou talvez eu esteja apenas trabalhando no campo errado, quem sabe). E também como eu mencionei no pretexto para o Java loop for-each (alguns se referem a ele como loop Iterator e outros como loop for-in ), é menos provável que você bata nesse bug estúpido em particular ao usá-lo. E antes de debater como isso pode até ser mais rápido do que os outros, lembre-se de que o javac não otimiza o bytecode de forma alguma (bem, quase de qualquer maneira), apenas o compila.
Se você gosta de micro-otimização e / ou seu software usa muitos loops recursivos e outros, então você pode estar interessado no terceiro tipo de loop. Lembre-se de avaliar bem seu software antes e depois de alterar os loops for, para esse estranho e micro-otimizado.
fonte
get(int)
, o outro usa umIterator
. ConsidereLinkedList
onde o desempenho defor(int i=0;i<strings.size();i++) { /* do something using strings.get(i) */ }
é muito pior, uma vez que está ocorrendoget(int)
n vezes.O loop for-each geralmente deve ser preferido. A abordagem "get" pode ser mais lenta se a implementação da lista que você está usando não suportar acesso aleatório. Por exemplo, se um LinkedList for usado, você incorreria em um custo transversal, enquanto a abordagem for-each usa um iterador que monitora sua posição na lista. Mais informações sobre as nuances do loop for-each .
Eu acho que o artigo está aqui agora: nova localização
O link mostrado aqui estava morto.
fonte
Bem, o impacto no desempenho é praticamente insignificante, mas não é zero. Se você observar o JavaDoc da
RandomAccess
interface:E para cada loop está usando a versão com o iterador,
ArrayList
por exemplo, para cada loop não é mais rápido.fonte
Iterable
s, mas não matrizes. Para matrizes, um loop for com uma variável de índice é usado. Há informações sobre isso no JLS .Parece haver uma diferença, infelizmente.
Se você observar o código de bytes gerado para os dois tipos de loops, eles serão diferentes.
Aqui está um exemplo do código fonte do Log4j.
Em /log4j-api/src/main/java/org/apache/logging/log4j/MarkerManager.java, temos uma classe interna estática chamada Log4jMarker, que define:
Com laço padrão:
Com para cada um:
O que há com esse Oracle?
Eu tentei isso com Java 7 e 8 no Windows 7.
fonte
É sempre melhor usar o iterador em vez de indexar. Isso ocorre porque o iterador provavelmente é otimizado para a implementação da Lista, enquanto o indexado (chamando get) pode não ser. Por exemplo, LinkedList é uma lista, mas a indexação através de seus elementos será mais lenta que a iteração usando o iterador.
fonte
O foreach torna a intenção do seu código mais clara e, normalmente, é preferível a uma melhoria muito pequena da velocidade - se houver.
Sempre que vejo um loop indexado, tenho que analisá-lo um pouco mais para garantir que ele faça o que penso que faz. Por exemplo, começa do zero, inclui ou exclui o ponto final etc.?
Parece que passo a maior parte do tempo lendo código (que escrevi ou que alguém escreveu) e a clareza é quase sempre mais importante que o desempenho. Hoje em dia é fácil descartar o desempenho porque o Hotspot faz um trabalho incrível.
fonte
O código a seguir:
Dá a seguinte saída no meu sistema:
Estou executando o Ubuntu 12.10 alpha com OracleJDK 1.7, atualização 6.
Em geral, o HotSpot otimiza muitos indirecionamentos e operações reduntantes simples; portanto, em geral, você não deve se preocupar com eles, a menos que haja muitos deles em seqüência ou estejam aninhados.
Por outro lado, o índice indexado no LinkedList é muito mais lento do que chamar o LinkedList no próximo iterador, para evitar o impacto no desempenho, mantendo a legibilidade ao usar os iteradores (explícita ou implicitamente em cada loop).
fonte
Mesmo com algo como um ArrayList ou Vector, em que "get" é uma simples pesquisa de array, o segundo loop ainda possui sobrecarga adicional que o primeiro não. Eu esperaria que fosse um pouco mais lento que o primeiro.
fonte
A única maneira de saber com certeza é compará-la, e mesmo isso não é tão simples quanto parece . O compilador JIT pode fazer coisas muito inesperadas no seu código.
fonte
Aqui está uma breve análise da diferença apresentada pela equipe de desenvolvimento do Android:
https://www.youtube.com/watch?v=MZOf3pOAM6A
O resultado é que não é uma diferença, e em ambientes muito contido com listas muito grandes que poderia ser uma diferença notável. Nos testes, o ciclo de cada loop levou o dobro do tempo. No entanto, o teste foi realizado em uma lista de matrizes de 400.000 números inteiros. A diferença real por elemento na matriz era de 6 microssegundos . Eu não testei e eles não disseram, mas esperaria que a diferença fosse um pouco maior usando objetos em vez de primitivos, mas mesmo assim, a menos que você esteja construindo um código de biblioteca em que não tenha idéia da escala do que será solicitado para repetir, acho que não vale a pena enfatizar a diferença.
fonte
Pelo nome da variável
objectArrayList
, presumo que seja uma instância dejava.util.ArrayList
. Nesse caso, a diferença de desempenho seria imperceptível.Por outro lado, se for um exemplo
java.util.LinkedList
, a segunda abordagem será muito mais lenta que aList#get(int)
é uma operação O (n).Portanto, a primeira abordagem é sempre preferida, a menos que o índice seja necessário pela lógica no loop.
fonte
Ambos fazem o mesmo, mas para um uso fácil e seguro da programação de cada um, há possibilidades de propensão a erros na segunda maneira de usar.
fonte
É estranho que ninguém tenha mencionado o óbvio - o foreach aloca memória (na forma de um iterador), enquanto um loop for normal não aloca nenhuma memória. Para jogos no Android, isso é um problema, porque significa que o coletor de lixo será executado periodicamente. Em um jogo, você não quer que o coletor de lixo funcione ... NUNCA. Portanto, não use loops foreach no método draw (ou render).
fonte
A resposta aceita responde à pergunta, além do caso excepcional de ArrayList ...
Como a maioria dos desenvolvedores confia no ArrayList (pelo menos acredito que sim)
Portanto, sou obrigado a adicionar a resposta correta aqui.
Diretamente da documentação do desenvolvedor: -
O loop for aprimorado (também conhecido como loop "for-each") pode ser usado para coleções que implementam a interface Iterável e para matrizes. Com coleções, um iterador é alocado para fazer chamadas de interface para hasNext () e next (). Com um ArrayList, um loop contado manuscrito é cerca de 3x mais rápido (com ou sem JIT), mas para outras coleções, a sintaxe aprimorada para loop será exatamente equivalente ao uso explícito do iterador.
Existem várias alternativas para iterar através de uma matriz:
zero () é o mais lento, porque o JIT ainda não pode otimizar o custo de obter o comprimento da matriz uma vez para cada iteração no loop.
um () é mais rápido. Ele puxa tudo para as variáveis locais, evitando as pesquisas. Somente o comprimento da matriz oferece um benefício de desempenho.
two () é mais rápido para dispositivos sem um JIT e indistinguível de um () para dispositivos com um JIT. Ele usa a sintaxe aprimorada para loop introduzida na versão 1.5 da linguagem de programação Java.
Portanto, você deve usar o loop for aprimorado por padrão, mas considere um loop contado manuscrito para a iteração ArrayList de desempenho crítico.
fonte
Sim, a
for-each
variante é mais rápida que o normalindex-based-for-loop
.for-each
usos variantesiterator
. Assim, o deslocamento é mais rápido que ofor
loop normal, que é baseado em índices.Isso ocorre porque eles
iterator
são otimizados para percorrer, porque estão apontando antes do próximo elemento e logo após o elemento anterior . Uma das razões paraindex-based-for-loop
ser lento é que, é necessário calcular e mover para a posição do elemento sempre que não estiver com oiterator
.fonte
fonte