Alors voilà j'me pose une question importante en java
Jusqu'à maintenant, pour parcourir mes objets dans les Arraylist, je faisais tout le temps :
for (Objet o : liste l)
if (o.estLeBonObjet()){
faire un truc();
break;
}
mais mon prof m'a dit que c'était super mal de faire ça, et qu'il fallait plutôt faire :
int i=0;
while(i<liste.size()){
if (liste.get(i).estLeBonObjet()){
faire un truc;
break;
}
i++;
}
en me disant que c'était beaucoup plus optimisé et rapide.
mais je comprend pas pourquoi, pour moi ça revient exactement au même
Il m'a dit que la première méthode forçait la liste à être parcourue entièrement, c'est vrai
comment ça marche ce for en fait du coup ![]()
Non, pour moi c'est n'importe quoi.
Le "for each" est basé sur un Iterator fail-fast en interne et c'est la façon la plus propre d'itérer une collection (pas forcément une liste).
L'exemple avec while est d'autant plus maladroit qu'on aurait pu utiliser la syntaxe
for(int i = 0; i < liste.size(); i++)
{}
plus élégante mais déjà plus moche que l'iterator. D'un point de vue pratique pour une VM, une construction "for( : )" est facile à optimiser (désactivation des bounds checking et tout ça).
Bref c'est un faux débat de toutes façons car si on souhaitait faire de la recherche dans une liste en prenant vraiment en compte la vitesse, y'aurait des systèmes beaucoup plus rapides qu'une itération.
Okay, ça confirme ce que je pensais
![]()
Je pense que tu pourrais aussi te renseigner sur les "Generics" (types génériques).
Ca te permettra de te passer du test de type dans le cas de Collections homogène.
C'est juste mais ça c'est plus une question de sécurité parce que les génériques en java sont perdus à la compilation (type erasure).
Dans C# en revanche, les génériques sont conservés et utilisés pour des optimisations en plus d'être carrément supérieurs en terme de possibilités. Rétrocompatibilité quand tu nous tiens.
Vi, mais ça lui permettrai de virer le fait qu'il s'amuse avec des "Object" ![]()
C'est principalement pour ça en fait.
J'ai essayé de créer une Arraylist de points, de parcourir cette liste et en suite d'afficher le temps que ça mettait, et finalement avec la méthode de mon prof ça va environ 100 fois plus vite qu'avec un for each
J'suis surpris mais il avait raison, je suppose ![]()
Hum, à mon avis ça dépend de ce que tu fais dans ta boucle.
Peut être que le compilateur optimise la boucle while bien mieux que le foreach dans ce cas précis. Ou bien que ta JVM a un comportement trivial.
Par contre fait gaffe, ArrayList implémente ça : http://download.oracle.com/javase/1.4.2/docs/api/java/util/RandomAccess.html
Mais pas les autres, donc il se peut que le foreach soit une bien meilleure pratique, histoire de ne pas se retrouver avec un réel problème de performance.
Le mieux c'est de profiler le code et de chercher la meilleure façon d'itérer une fois que tu as terminé ton application. ![]()
ba disons que toi tu as une affectation et lui non apparament.
A chaque fois tu met l'objet de la liste dans un Objet o.
java peut avoir des performances tres tres etrange. Je conseillerais de ne pas se preoccuper des performance trop tot dans le developpement de l'application et de voir a la fin ce qui prend du temps et si ca vaut le coup de se faire chier.
De facon general, si le langage a une construction dedie pour une operation, il est preferable de l'utiliser. Elle sera certainement optimiser plus tard dans le developpement du compilateur (ou machine virtuelle)
Wokay, intéressant, ![]()
Attends, c'est quoi 100 fois plus vite? Mesurée comment?
Parce qu'il faut se méfier des microbenchmarks, et surtout faire attention au fait que le code java s'optimise au fur et à mesure et il se peut tout à fait que la méthode foreach ait nécessité de JITer des classes jusque là inutiles.
Poste le code de ton test et on pourra en reparler. Car selon "Effective java" que je possède, un foreach a des chances d'être plus rapide qu'un for.
Désolé pour le retard
J'avais fait un truc comme ça :
http://www.copypastecode.com/65155/
et même en inversant les deux boucles ça revenait au même donc j'en ai conclu que le for each était moins rapide pour ce cas là ![]()
Flemme de tester mais si tu fais ça, normalement tes boucles tournent même pas 1 seul tour.
Ah bon ? ![]()
Il les supprime tout seul parce que rien est véritablement fait dedans ?
Dans ce cas pourquoi y'a quand même une sacrée différence de temps ? ![]()
Même en faisant des opérations
http://www.copypastecode.com/65163/
le résultat est le même :doutoe:
Déjà il y a un truc valable pour tous les langages JIT : tu peux jamais te fier à la première exécution d'un algo pour juger de son temps sans warmup.
Ensuite par rapport à ton code, fait un system.out.println de arraylist.size() pour voir de quoi je parle.
On peut m'expliquer pourquoi les listes sont vides ? ![]()
Parce que size() c'est pas la capacité actuelle de la liste mais bel et bien le nombre d'objets contenu. Or quand tu viens juste de la créer, ce nombre c'est 0.
Donc une boucle
for(int i = 0; i < 0; i++)
Ca tourne pas longtemps.
Mince, j'me suis foutu la honte là ![]()
Merci
Ouais du coup maintenant la boucle la plus lente est celle qui démarre en premier à cause de ce fameux warm up j'imagine
Donc pour parcourir une liste entièrement vaut mieux toujours utiliser un for each (en plus si on change de type de collection ça marchera toujours rapidement) plutôt que d'utiliser un for / while qui est moins lisible et qui va au final aussi vite
C'était intéressant
![]()