Java: Bir Koleksiyonda yinelemenin en iyi yolu (burada ArrayList)


99

Bugün zaten yüzlerce kez kullandığım bir kod parçasına ulaştığımda mutlu bir şekilde kod yazıyordum:

Bir Koleksiyon boyunca yineleme (burada ArrayList)

Bazı nedenlerden dolayı, Eclipse'in otomatik tamamlama seçeneklerine gerçekten baktım ve beni meraklandırdı:

Aşağıdaki döngüler hangi durumlarda diğerlerinden daha iyidir?

Klasik dizi indeksi döngüsü:

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

YineleyicideNext () / next ():

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

Ve favorim çünkü yazması çok basit:

for (iterable_type iterable_element : collection) {

}

2
Bana gelince çoğunlukla 3. döngüyü kullanıyorum.
Harry Joy

1
İkinci yol için kullanmak daha iyidir:for (Iterator<type> iterator = collection.iterator(); iterator.hasNext();) { type type = iterator.next(); }
mike jones

4
Koleksiyon arabirimi bir "alma" yöntemi içermez, bu nedenle ilki her zaman mümkün değildir.
ThePerson

Ayrıca ilk seçenekte, 'for döngüsü' için, collection.length, collection.size () olarak değiştirilmelidir
Vishwathma

Yanıtlar:


106

İlki, öğenin dizinine de ihtiyacınız olduğunda kullanışlıdır. Bu temelde ArrayLists'nin diğer iki çeşidine eşdeğerdir , ancak a kullanırsanız gerçekten yavaş olacaktır LinkedList.

İkincisi, öğenin dizinine ihtiyacınız olmadığında, ancak yineleme yaparken öğeleri kaldırmanız gerektiğinde kullanışlıdır. Ancak bu biraz fazla ayrıntılı IMO olma dezavantajına sahiptir.

Üçüncü versiyon da benim tercih ettiğim seçimdir. Kısadır ve herhangi bir dizine veya temel yineleyiciye ihtiyaç duymadığınız tüm durumlar için çalışır (yani yalnızca öğelere erişiyorsunuz, onları kaldırmıyorsunuz veya Collectionherhangi bir şekilde değiştirmiyorsunuz - bu en yaygın durumdur).


3
+1 döv beni. LinkedList (değil söz gidiyordu tüm Collection 'ın dizine göre almak için ucuz).
The Scrum Meister

Öğelerin yalnızca döngü halinde olması gerektiği sürece, 3. sürümü kullanmak her zaman iyidir, çünkü uygulama tüm farklı Koleksiyonlar için zaten mevcuttur ve Sun veya herhangi bir JDK uygulaması, her biri yerine performansı iyileştirmeye çalışır.
Phani

@Phani: Diğer iki değişken de herhangi bir JDK uygulaması üzerinde çalışıyor.
MAK

Bunların işe yaramayacağını söylemedim, ancak herhangi bir şans eseri koleksiyonların uygulanması için belirli bir iyileştirme veya performans değişikliği yapılırsa, o zaman kodunuz için otomatik olarak geçerli olur ve performansı artırmak için yazmanıza gerek yoktur. demek istediğim bu.
Phani

1
@Phani: AFAIK 3. form, 2. form için yalnızca sözdizimsel şekerdir (yani, başlık altında foreach varyantı aslında bir yineleyici kullanır). Dolayısıyla, performans avantajları her iki varyant için de mevcut olmalıdır. İlk sürüm elbette herhangi bir performans avantajı sağlamayacaktır (örneğin List, bir ağaç olarak uygulanırsa, aslında daha yavaş olacaktır).
MAK

37

Hepsinin kendi kullanımları var:

  1. Tekrarlanabilir bir cihazınız varsa ve koşulsuz olarak hepsine geçmeniz gerekiyorsa:

    for (iterable_type iterable_element: collection)

  2. Yinelenebilir ancak koşullu olarak geçiş yapmanız gerekiyorsa:

    için (Yineleyici iterator = collection.iterator (); iterator.hasNext ();)

  3. Veri yapısı yinelenebilir uygulamazsa:

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


İlk yöntemi koşullu olarak geçmek için bunu yapabilir misiniz: if (iterable_element.some_attribute) {// bir şeyler yapın; } else {// hiçbir şey yapmayın; }. Eğer evet ise, o zaman birinci ve ikinci yöntem arasında sözdizimsel şeker dışında esasen hiçbir fark yoktur.
Thomas Nguyen

1 tıpkı diğerleri gibi breakve / veyacontinue
arcyqwerty'yi

13

Java 8 ile ayrıca koleksiyonların akışı () kullanılır

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

veya

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

Java 8 akışı ve merak edenler için koleksiyonlar hakkında daha fazla bilgi bağlantısı


4

Hiçbiri diğerlerinden "daha iyi" değil. Üçüncüsü, benim için daha okunabilir, ancak ön kısımları kullanmayan biri için tuhaf görünebilir (ilkini tercih edebilirler). 3'ü de Java'yı anlayan herkes için oldukça açıktır, bu nedenle kod hakkında hangisi daha iyi hissetmenizi sağlarsa onu seçin.

İlki en temel olanıdır, bu yüzden en evrensel modeldir (diziler için çalışır, aklıma gelen tüm yinelemeler). Aklıma gelen tek fark bu. Daha karmaşık durumlarda (örneğin, mevcut dizine erişiminizin olması veya listeyi filtrelemeniz gerekir), sırasıyla birinci ve ikinci durumlar daha anlamlı olabilir. Basit durum için (yinelenebilir nesne, özel gereksinimler yok), üçüncüsü en temiz görünüyor.


2

İlk seçenek performans açısından daha iyidir (ArrayList'in RandomAccess arabirimini uyguladığı gibi). Java belgesine göre, sınıfın tipik örnekleri için bu döngü aşağıdaki durumlarda bir List uygulaması RandomAccess arabirimini uygulamalıdır:

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

bu döngüden daha hızlı çalışır:

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

Umut ediyorum bu yardım eder. Sıralı erişim listeleri için ilk seçenek yavaş olacaktır.


1

İşte bir örnek

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

             }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.