54

次のシナリオを検討してください。

List<String> list = new ArrayList<>();

Stringここで、このリストの値を追加しました。

次の方法を使用して、リスト内のすべての要素に移動しました。

オプションワンユースfor-each

for (String i : list) {
        System.out.println(i);
    } 

オプション 2 使用Iterator

Iterator it=list.iterator();
while (it.hasNext()){
   System.out.println(it.next());
}

for-eachの代わりに使用すると、パフォーマンス上の利点があるかどうかを知りたいだけですIterator。また、Javaでイテレータを使用するのは悪い習慣ですか?

4

8 に答える 8

18

違いは主にシンタックス シュガーですが、Iterator は反復している Collection からアイテムを削除できる点が異なります。技術的には、強化された for ループを使用すると、少なくともコレクションと配列の両方を含む Iterable であれば何でもループできます。

パフォーマンスの違いについて心配する必要はありません。このようなマイクロ最適化は、気を散らすものではありません。途中でアイテムを削除する必要がある場合は、Iterator を使用します。それ以外の場合、 for ループは読みやすいという理由だけで使用される傾向があります。

for (String s : stringList) { ... }

対:

for (Iterator<String> iter = stringList.iterator(); iter.hasNext(); ) {
  String s = iter.next();
  ...
}
于 2013-08-29T11:02:23.117 に答える
12

for-each高度なループ構造です。内部的に Iterator を作成し、Collection を反復処理します。コンストラクトに対して実際の Iterator オブジェクトを使用する唯一の利点は、for-eachのような Iterator のメソッドを使用してコレクションを変更できることです.remove()。反復中に Iterator のメソッドを使用せずにコレクションを変更すると、ConcurrentModificationException が生成されます。

于 2013-08-29T10:59:59.600 に答える
3

これを行う最善の方法は、Java 8 です。

list.forEach(System.out::println);

ここにいくつかの便利なリンクがあります。

  1. Java 8 Iterable.forEach() と foreach ループ

  2. http://www.javaworld.com/article/2461744/java-language/java-language-iterating-over-collections-in-java-8.html

  3. https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html

于 2015-04-21T08:12:07.057 に答える
1

以下は、Java バージョン 8 で実行された のトラバーサルに対するFor-eachvs Iteratorvsのパフォーマンスをチェックするための簡単なコード スニペットです。forArrayList<String>

        long MAX = 2000000;

        ArrayList<String> list = new ArrayList<>();

        for (long i = 0; i < MAX; i++) {

            list.add("" + i);
        }

        /**
         * Checking with for each iteration.
         */
        long A = System.currentTimeMillis();

        for (String data : list) {
            // System.out.println(data);
        }

        long B = System.currentTimeMillis();
        System.out.println(B - A + "ms");

        /**
         * Checking with Iterator method
         */

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            iterator.next();
            // System.out.println(iterator.next());
        }

        long C = System.currentTimeMillis();
        System.out.println(C - B + "ms");

        /**
         * Checking with normal iteration.
         */
        for (int i = 0; i < MAX; i++) {
            list.get((int) (i % (MAX - i)));
            // System.out.println(list.get(i));
        }

        long D = System.currentTimeMillis();
        System.out.println(D - C + "ms");

平均出力値:

19ms
9ms
27ms

結果分析: Iterator (9ms) < For-each(19ms) < For(27ms)

ここではIterator最高のパフォーマンスForが得られ、最低のパフォーマンスが得られます。ただしFor-each、パフォーマンスはその中間にあります。

于 2018-02-08T07:15:58.197 に答える
0

リスト内のアイテムを置き換えたい場合は、 for ループを使用して古い学校に行きます

for (int nIndex=0; nIndex < list.size(); nIndex++) {
  Obj obj = (Obj) list.get(nIndex);

  // update list item
  list.set(nIndex, obj2);
}
于 2014-10-14T04:30:30.750 に答える
0

foreachとにかくフードの下でイテレータを使用します。それは本当に単なるシンタックスシュガーです。

次のプログラムを検討してください。

import java.util.List;
import java.util.ArrayList;

public class Whatever {
    private final List<Integer> list = new ArrayList<>();
    public void main() {
        for(Integer i : list) {
        }
    }
}

でコンパイルしてjavac Whatever.java
の逆アセンブルされたバイトコードを読み取りmain()ますjavap -c Whatever

public void main();
  Code:
     0: aload_0
     1: getfield      #4                  // Field list:Ljava/util/List;
     4: invokeinterface #5,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
     9: astore_1
    10: aload_1
    11: invokeinterface #6,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
    16: ifeq          32
    19: aload_1
    20: invokeinterface #7,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
    25: checkcast     #8                  // class java/lang/Integer
    28: astore_2
    29: goto          10
    32: return

foreachコンパイルすると、次のようなプログラムになることがわかります。

  • を使用してイテレータを作成しますList.iterator()
  • If Iterator.hasNext(): ループを呼び出しIterator.next()て続行する

「この無駄なループがコンパイルされたコードから最適化されないのはなぜですか?リスト項目で何もしないことがわかります」:まあ、.iterator()副作用のある反復可能オブジェクトをコーディングすることは可能です、または.hasNext()副作用または意味のある結果をもたらすもの。

データベースからのスクロール可能なクエリを表す iterable が何か劇的なことをする可能性があることは容易に想像できます.hasNext()(データベースに接続したり、結果セットの最後に到達したためにカーソルを閉じたりするなど)。

したがって、ループ本体で何も起こらないことを証明できたとしても、反復時に意味のある/結果的なことが何も起こらないことを証明するのは、よりコストがかかります (扱いにくい?)。コンパイラは、この空のループ本体をプログラムに残す必要があります。

期待できる最善の方法は、コンパイラの警告です。この空のループ本体について警告javac -Xlint:all Whatever.javaしないの興味深いことです。ただし、IntelliJ IDEA はそうします。確かに、Eclipse Compiler を使用するように IntelliJ を構成しましたが、それが理由ではないかもしれません。

ここに画像の説明を入力

于 2017-03-07T12:00:42.997 に答える