Maison >Java >javaDidacticiel >Analyse comparative des applications For et For-each dans les boucles Java
For-each n'est pas une nouvelle syntaxe, mais du sucre de syntaxe pour Java. Au moment de la compilation, le compilateur convertit ce code en implémentation d'itérateur et le compile en bytecode. Nous pouvons décompiler le code compilé suivant en exécutant la commande javap-verbose-Testforeach
: javap-verbose-Testforeach
反编译以下编译代码:
public class TestForeach { List<Integer> integers; public void testForeach(){ for(Integer i : integers){ } } }
获得的详细字节码如下:
public void testForeach(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=3, args_size=1 0: aload_0 1: getfield #2 // Field integers:Ljava/util/List; 4: invokeinterface #3, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 9: astore_1 10: aload_1 11: invokeinterface #4, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z 16: ifeq 32 19: aload_1 20: invokeinterface #5, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 25: checkcast #6 // class java/lang/Integer 28: astore_2 29: goto 10 32: return LineNumberTable: line 11: 0 line 13: 29 line 14: 32 LocalVariableTable: Start Length Slot Name Signature 29 0 2 i Ljava/lang/Integer; 0 33 0 this Ltest/TestForeach; }
此字节码的一般含义是使用getfileld
命令来获取integers
变量并且调用List.iterator
来获取迭代器实例和调用iterator.hasNext
。如果返回true
,调用iterator.next
public class ForLoopTest { public static void main(String[] args) { List<Integer> arrayList = new ArrayList<>(); for (int i = 0; i < 10000000; i++) { arrayList.add(i); } long arrayListStartTime = System.currentTimeMillis(); for (int i = 0; i < arrayList.size(); i++) { arrayList.get(i); } long arrayListCost =System.currentTimeMillis()-arrayListStartTime; System.out.println("ArrayList for loop traversal cost: "+ arrayListCost); long arrayListForeachStartTime = System.currentTimeMillis(); for (Integer integer : arrayList) { } long arrayListForeachCost =System.currentTimeMillis()-arrayListForeachStartTime; System.out.println("ArrayList foreach traversal cost: "+ arrayListForeachCost);Le bytecode détaillé obtenu est le suivant :
rrreee
La signification générale de ce bytecode est d'utiliser getfileld
pour obtenir la variable integers
et appelez List.iterator
pour obtenir l'instance de l'itérateur et appelez iterator.hasNext
. Si true
est renvoyé, appelez la méthode iterator.next
. Veuillez voir, il s'agit de la logique d'implémentation de l'itérateur traversant la collection. BenchmarkingMaintenant, testons en utilisant la méthode de boucle for et la méthode for-each. rrreeeVoici les résultats des tests :
Comme vous pouvez le constater, les résultats sont évidents. L’utilisation de la méthode de boucle For est plus efficace sur ArrayList que la méthode For each.
Peut-on dire que la boucle for est meilleure que la boucle for-each ?
La réponse est non. Dans le benchmark suivant, nous changeons ArrayList en LinkedList. Encore une fois, voici les résultats des tests.
Analyse des causes
Certains débutants peuvent se demander pourquoi ArrayList utilise la méthode de boucle for pour parcourir plus rapidement, alors que LinkedList est plus lent et très lent ?
Ceci est déterminé par les structures de données ArrayList et LinkedList.
ArrayList utilise des tableaux pour stocker les éléments en dessous. Les tableaux sont des espaces mémoire contigus. Les données peuvent être obtenues via des index. La complexité temporelle est O(1), donc c'est rapide. La couche inférieure de LinkedList est une liste doublement chaînée. Utilisez une boucle for pour implémenter le parcours, en commençant à chaque fois à partir du nœud principal de la liste chaînée. La complexité temporelle est O(n*n).Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!