Java:コレクション(ここではArrayList)を反復処理する最良の方法


98

今日、私はすでに何百回も使用したコードにたどり着いたとき、喜んでコーディングをしていました。

コレクションを反復処理する(ここではArrayList)

何らかの理由で、私は実際にEclipseのオートコンプリートオプションを見て、それが不思議に思いました。

次のループは他のループよりも使用に適していますか?

従来の配列インデックスループ:

for (int i = 0; i < collection.length; i++) {
  type array_element = collection.get(index);
}

イテレーターhasNext()/ next():

for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
  type type = (type) iterator.next();   
}

そして、私の好きなものはとても簡単に書くことができるからです:

for (iterable_type iterable_element : collection) {

}

2
それに関しては、私は主に3番目のループを使用します。
Harry Joy

1
:使用へのより良い第二の方法についてはfor (Iterator<type> iterator = collection.iterator(); iterator.hasNext();) { type type = iterator.next(); }
マイク・ジョーンズ

4
コレクションインターフェースにはメソッド「get」が含まれていないため、最初の方法が常に可能であるとは限りません。
ThePerson、2015

回答:


104

1つ目は、要素のインデックスも必要な場合に便利です。これは基本的にArrayListsの他の2つのバリアントと同等ですが、を使用すると本当に遅くなりますLinkedList

2つ目は、要素のインデックスは必要ないが、反復するときに要素を削除する必要がある場合に便利です。ただし、これにはIMOが少なすぎるという欠点があります。

3番目のバージョンも私の好みの選択です。これは短く、インデックスや基礎となるイテレータが必要ないすべての場合に機能します(つまり、要素にアクセスするだけで、要素を削除したり変更したりすることCollectionはありません。これが最も一般的なケースです)。


3
+1私を殴ってください。LinkedListについて言及する予定でした(すべて Collectionのがインデックスで取得するのに安価なわけではありません)。
スクラムマイスター

要素をループするだけでよい限り、3番目のバージョンを使用することは常に良いことです。実装はすべての異なるコレクションにすでに存在し、SunまたはJDKの実装はすべてではなくパフォーマンスの向上に努めています。
Phani

@Phani:他の2つのバリアントは、JDK実装でも機能します。
MAK、2011年

私はそれらが機能しないとは言いませんでしたが、万が一コレクションの実装に対して特定の改善またはパフォーマンスの変更が行われた場合、それは自動的にコードに適用され、パフォーマンスを向上させるために記述する必要はありません私が言いたいことです。
Phani

1
@Phani:AFAIKの3番目の形式は、2番目の形式の構文糖衣にすぎません(つまり、内部ではforeachバリアントは実際にはイテレータを使用しています)。したがって、パフォーマンス上の利点は両方のバリアントで利用できるはずです。もちろん、最初のバージョンでは、パフォーマンス上の利点は得られません(たとえばList、ツリーとして実装されている場合、実際には遅くなります)。
MAK、2011年

36

それらはすべて独自の用途があります:

  1. イテラブルがあり、それらすべてに無条件にトラバースする必要がある場合:

    (iterable_type iterable_element:コレクション)

  2. イテラブルがあるが条件付きでトラバースする必要がある場合:

    for(Iterator iterator = collection.iterator(); iterator.hasNext();)

  3. データ構造が反復可能を実装しない場合:

    for(int i = 0; i <collection.length; i ++)


これを実行して、最初のメソッドを条件付きでトラバースできますか。if(iterable_element.some_attribute){//何かを実行します。} else {//何もしない; }。はいの場合、構文糖以外は最初の方法と2番目の方法の間に本質的に違いはありません。
Thomas Nguyen

1は、条件付きで他のユーザーと同じようにトラバースできます。breakまた、/またはcontinue
arcyqwerty 2017

13

さらに、Java 8にはコレクションのstream()ユーティリティがあります。

collection.forEach((temp) -> {
            System.out.println(temp);
});

または

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

Java 8ストリームと驚異のコレクションの詳細リンク


4

それらのどれも他のものより「良い」ものではありません。3つ目は、私にとってはより読みやすいですが、foreachを使用しない人にとっては奇妙に見えるかもしれません(最初のものを好むかもしれません)。3つすべては、Javaを理解しているすべての人にとってかなり明確であるため、コードについて気分がよくなる方を選択してください。

最初のものは最も基本的なものなので、それは最も普遍的なパターンです(配列で機能し、私が考えることができるすべての反復可能です)。それが私が考えることができる唯一の違いです。より複雑な場合(たとえば、現在のインデックスにアクセスする必要がある場合、またはリストをフィルター処理する必要がある場合)は、最初のケースと2番目のケースがそれぞれ意味をなす場合があります。単純なケース(反復可能なオブジェクト、特別な要件なし)の場合、3番目が最もクリーンなようです。


2

最初のオプションは、より優れたパフォーマンスです(ArrayListはRandomAccessインターフェイスを実装するため)。Java docによると、List実装は、クラスの一般的なインスタンスで次のループが行われる場合にRandomAccessインターフェースを実装する必要があります。

 for (int i=0, n=list.size(); i < n; i++)
     list.get(i);

このループよりも速く実行されます:

 for (Iterator i=list.iterator(); i.hasNext(); )
     i.next();

お役に立てば幸いです。順次アクセスリストの場合、最初のオプションは遅くなります。


1

ここに例があります

Query query = em.createQuery("from Student");
             java.util.List list = query.getResultList();
             for (int i = 0; i < list.size(); i++) 
             {

                 student = (Student) list.get(i);
                 System.out.println(student.id  + "  " + student.age + " " + student.name + " " + student.prenom);

             }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.