2015-04-23 14 views
5

Büyük olasılıkla aşırı verimli olmaya çalışıyorum, ancak aşağıdaki iki kod örneğinden hangisinin daha hızlı çalışacağını merak ediyorum.Döngü için kısa yol tekrar edilebilir referansın önbelleğini mu?

Bir ArrayListStrings içeren bir nesneye başvurunuz olduğunu ve bu listede yinelemek istediğinizi varsayalım. Aşağıdakilerden hangisi daha verimli (sadece marjinal olsa bile)? Gördüğünüz gibi ilk örnek yapar göründüğü gibi

for(String s : foo.getStringList()) 
    System.out.println(s); 

Ya

ArrayList<String> stringArray = foo.getStringList(); 
for(String s : stringArray) 
    System.out.println(s); 

, ikinci döngü yerine bunun için her yinelemesini çağıran listesine bir başvuru başlatır. Bu kavram tamamen yanlış olmadıkça ve her ikisi de aynı şekilde işlerler, çünkü Java'nın iç çalışması kendi referans değişkenini yaratır.

Benim sorum şu ki, hangisi?

+0

CS kurslarına geri dönmeyi düşünüyorum. Bence eşdeğer olurlar. Programı bir hata ayıklayıcıda çalıştırarak bunu gözlemlemeniz gerekir. Değişken listesinde 'foo.getStringList()' – Freiheit

+0

'dan döndürülen nesneye bir çeşit başvuru olması gerekir. İkinci koddaki stringArray'ın kapsamı geniş olduğundan her zaman ilk seçenekle birlikte giderim. Kapsamı olabildiğince dar tutmayı tercih ediyorum. – Jimmy

+0

@Jimmy, ancak aynı değişken adını tekrar kullanmayacaksanız ve diğer sınıf listede anwyays tutmaya devam ederseniz, kapsam sorunu mu? – StrongJoshua

cevap

6

Hiçbir fark yoktur, çünkü her iki döngü yalnızca döngünün başında ifade için bir yineleyiciye bir başvuru almayı sürdürür. İşte Java Language Specification bir alıntı var:

deyimi için formun deyimi için temel eşdeğerdir geliştirilmiş:

for (I #i = Expression.iterator(); #i.hasNext();) { 
    VariableModifiersopt TargetType Identifier = 
     (TargetType) #i.next(); 
    Statement 
} 
+0

Java kaynağını gösterdiğiniz için teşekkür ederiz! Şimdi, bu ifadeleri çıkarabileceğimi biliyorum (her zaman ikinci örneği yaptım). – StrongJoshua

3

Ben olasılığı çalışıyorum aşırı verimli

Kesinlikle öyle. 'u denemeyin, okunabilir bir kod yazınız ve iyi olacak. standart kod olarak iyi ve hızlı, derleyici çocuklar en dikkat çeken şeydir. Neyin verimli olduğu konusunda iyi bir tahminde bulunabilmek için gerçekten Java hakkında çok şey bilmeniz gerekir (ve asla emin olamazsınız). Gördüğünüz gibi

, ikinci döngü yerine bunun için her yineleme

arayarak listesine bir başvuru başlatır Ve böylece ilk döngü yapar. Niye ya? Bunun olmadığını düşünün. foo.getStringList()'un her çağrıldığında başka bir şey döndüreceğini düşünün. Nasıl yineleyebilirsin? Her Iterable'un bir List olduğu gibi, endeksleri kullanmanın sayılmadığını unutmayın.

Her bir döngü, Iterator'u kullanmanın kısayoludur. Bir Iterator sadece bir kez elde edilir ve daha sonra hasNext ve next buna çağrılır. Açıkçası, Iterable'u birden çok kez değerlendirecek yer yok. İyi bir algoritma ve/veya veri yapısını kullanarak


farklı bir hikayedir. Kabarcık gibi şeyler kaçınılmalıdır.

3

Evet.Eğer (javap -v ile) gibi bir yöntemin bayt kodu incelemek eğer steno formu

public static void main(String[] args) { 
    List<String> al = Arrays.asList("a", "b"); 
    for (String str : al) { 
     System.out.println(str); 
    } 
} 

Eğer invokeinterface #28, 1 sadece

public static void main(java.lang.String[]); 
    descriptor: ([Ljava/lang/String;)V 
    flags: ACC_PUBLIC, ACC_STATIC 
    Code: 
     stack=4, locals=4, args_size=1 
     0: iconst_2 
     1: anewarray  #16     // class java/lang/String 
     4: dup 
     5: iconst_0 
     6: ldc   #18     // String a 
     8: aastore 
     9: dup 
     10: iconst_1 
     11: ldc   #20     // String b 
     13: aastore 
     14: invokestatic #22     // Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List; 
     17: astore_1 
     18: aload_1 
     19: invokeinterface #28, 1   // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 
     24: astore_3 
     25: goto   45 
     28: aload_3 
     29: invokeinterface #34, 1   // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 
     34: checkcast  #16     // class java/lang/String 
     37: astore_2 
     38: getstatic  #40     // Field java/lang/System.out:Ljava/io/PrintStream; 
     41: aload_2 
     42: invokevirtual #46     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     45: aload_3 
     46: invokeinterface #52, 1   // InterfaceMethod java/util/Iterator.hasNext:()Z 
     51: ifne   28 
     54: return 
kez denir görecekti, döngünün her tekrarında yineleyici yeniden getirmeye değil
+0

Teknik olarak, örneğiniz, listeyi almak için ikinci bir sınıfınız olmadığından ikinci örneğim gibidir. – StrongJoshua

+0

@StrongJoshua Buradaki nokta size bayt kodunu ve sadece "yineleyici" yi bir kez nasıl aldığını göstermekti. –

+0

Haklısın, anlıyorum. Teşekkür ederim :) – StrongJoshua

İlgili konular