ホームページ  >  記事  >  Java  >  Java ループでの For アプリケーションと For-each アプリケーションの比較分析

Java ループでの For アプリケーションと For-each アプリケーションの比較分析

王林
王林転載
2023-05-25 14:56:081140ブラウズ

for-each 実装メソッド

For-each は新しい構文ではなく、Java の構文シュガーです。コンパイル時に、コンパイラーはこのコードをイテレーター実装に変換し、バイトコードにコンパイルします。コマンド 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 メソッドを呼び出します。

ご覧ください。これは、コレクションを走査するイテレーターの実装ロジックです。

ベンチマーク

次に、for ループ メソッドと for-each メソッドを使用してテストしてみましょう。

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);

テスト結果は次のとおりです:

Java ループでの For アプリケーションと For-each アプリケーションの比較分析

ご覧のとおり、結果は明らかです。 ArrayList では、For each メソッドよりも For ループ メソッドを使用する方が効率的です。

for ループは for-each よりも優れていると言えるでしょうか?

答えは否定的です。次のベンチマークでは、ArrayList を LinkedList に変更します。

繰り返しになりますが、テスト結果は次のとおりです。

Java ループでの For アプリケーションと For-each アプリケーションの比較分析

原因分析

初心者の中には、なぜ ArrayList が for ループ メソッドを使用して高速に移動するのに、LinkedList は低速で​​非常に遅いのか疑問に思う人もいるかもしれません。

これは、ArrayList および LinkedList データ構造によって決まります。

ArrayList の最下層は、配列を使用して要素を格納します。配列は連続したメモリ空間です。データはインデックスを通じて取得できます。時間計算量は O(1) なので高速です。

LinkedList の最下層は二重リンク リストです。 for ループを使用して、毎回リンク リストの先頭ノードから開始するトラバーサルを実装します。時間計算量は O(n*n) です。

結論

  • ArrayList を使用する場合、for-each は反復子によって実装され、同時変更検証を実行する必要があるため、for ループ メソッドの方が高速です。

  • LinkedList を使用する場合、LinkedList は二重リンク リストを使用して実装されているため、for-each は for ループよりもはるかに高速です。すべてのアドレス指定はヘッド ノードから開始する必要があります。 LinkedList を反復処理するときは、for ループの使用を避けてください。

  • 反復子パターンを使用すると、for-each はコレクションの特定の実装を気にする必要がありません。コレクションを置換する必要がある場合は、コードを変更せずに簡単に行うことができます。

以上がJava ループでの For アプリケーションと For-each アプリケーションの比較分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。