dlaczego enhanced For loop jest bardziej wydajny niż normalna for loop

Czytałem, że enhanced for loop jest bardziej wydajny niż normalny For loop tutaj:

Http://developer.android.com/guide/practices/performance.html#foreach

Kiedy szukałem różnicy między ich efektywnością, znalazłem tylko: w przypadku normalnej pętli for potrzebujemy dodatkowego kroku, aby dowiedzieć się długości tablicy lub rozmiaru itp.,

for(Integer i : list){
   ....
}


int n = list.size();
for(int i=0; i < n; ++i){
  ....
}

Ale czy to jedyny powód, dla którego pętla enhanced for jest lepsza niż normalna pętla for? W w tym przypadku lepiej użyć normalnej dla pętli ze względu na niewielką złożoność zrozumienia rozszerzonej dla pętli.

Sprawdź to dla interesującego problemu: http://www.coderanch.com/t/258147/java-programmer-SCJP/certification/Enhanced-Loop-Vs-Loop

Czy ktoś może wyjaśnić wewnętrzną implementację tych dwóch typów pętli for, lub wyjaśnić inne powody, dla których należy używać rozszerzonej pętli for?

Author: user unknown, 2012-07-19

7 answers

To trochę uproszczone powiedzieć, że enhanced For loop jest bardziej wydajny. To Może być, ale w wielu przypadkach jest to prawie dokładnie to samo, co pętla old-school.

Pierwszą rzeczą, na którą należy zwrócić uwagę jest to, że pętla enhanced for używa Iterator, więc jeśli ręcznie iterujesz nad kolekcją używając Iterator, powinieneś mieć prawie taką samą wydajność, jak pętla enhanced for.

Miejsce, w którym pętla enhanced for jest szybsza niż naiwnie zaimplementowana pętla tradycyjna jest czymś takim:

LinkedList<Object> list = ...;

// Loop 1:
int size = list.size();
for (int i = 0; i<size; i++) {
   Object o = list.get(i);
   /// do stuff
}

// Loop 2:
for (Object o : list) {
  // do stuff
}

// Loop 3:
Iterator<Object> it = list.iterator();
while (it.hasNext()) {
  Object o = it.next();
  // do stuff
}

W Tym Przypadku Loop 1 będzie wolniejszy od Loop 2 i Loop 3, ponieważ będzie musiał (częściowo) przemierzać listę w każdej iteracji, aby znaleźć element na pozycji i. Pętle 2 i 3 będą jednak tylko o jeden element dalej na liście, ze względu na użycie Iterator. Loop 2 i 3 również będą miały prawie taką samą wydajność, ponieważ Loop 3 jest prawie dokładnie tym, co kompilator wytworzy kiedy piszesz kod w pętli 2.

 46
Author: Joachim Sauer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-19 07:00:01

Jestem zaskoczony małym eksperymentem, który przeprowadziłem dzisiaj z wyżej wymienionymi punktami. Więc to, co zrobiłem, to to, że wstawiłem pewną liczbę elementów do połączonej listy i iterowałem przez nią za pomocą wyżej wymienionych trzech metod 1) używając advanced for loop 2) używając iteratora 3) używając simple loop I get ()
Myślę, że programiści tacy jak wy mogą lepiej zrozumieć, co zrobiłem, widząc kod.

long advanced_timeElapsed,iterating_timeElapsed,simple_timeElapsed;
    long first=System.nanoTime();
    for(Integer i: myList){
        Integer b=i;
    }
    long end= System.nanoTime();
    advanced_timeElapsed=end-first;
    System.out.println("Time for Advanced for loop:"+advanced_timeElapsed);
    first=System.nanoTime();
    Iterator<Integer> it = myList.iterator();
    while(it.hasNext())
    {
        Integer b=it.next();
    }
    end= System.nanoTime();
    iterating_timeElapsed=end-first;
    System.out.println("Time for Iterating Loop:"+iterating_timeElapsed);
    first=System.nanoTime();
    int counter=0;
    int size= myList.size();
    while(counter<size)
    {
        Integer b=myList.get(counter);
        counter++;  
    }
    end= System.nanoTime();
    simple_timeElapsed=end-first;
    System.out.println("Time for Simple Loop:"+simple_timeElapsed);

Wyniki, gdzie nie tego się spodziewałem . Poniżej znajduje się Wykres czasu upłynął w 3 przypadkach. Wykres Upływu Czasu

Oś Y-czas upłynął Oś X-przypadek testowy
test case1: 10 wejść
test case2: 30 wejść
test case3: 50 wejść
obudowa testowa 4: 100 wejść
test case5: 150 wejść
obudowa testowa 6: 300 wejść
test case7: 500 wejść
obudowa testowa 8: 1000 wejść
test case9: 2000 wejść
przypadek testowy10: 5000 wejść
obudowa testowa11: 10000 wejść
przypadek testowy12: 100000 wejść

Tutaj widać, że prosta pętla działa o wiele lepiej niż inne.jeśli znajdź wszelkie błędy w powyższym kodzie, odpowiedz, a ja sprawdzę ponownie. zaktualizuje się dalej po tym, jak przekopię się przez bytecode i zobaczę, co dzieje się pod maską. Przepraszam za tak długą odpowiedź, ale lubię być opisowy. Filip

 8
Author: Philip George,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-28 09:55:05

Czytałem, że enhanced For loop jest wydajny niż normalnie for loop.

Faktycznie czasami jest mniej wydajny dla programu, ale przez większość czasu jest dokładnie taki sam.

Jest bardziej wydajny dla programisty, co często jest znacznie ważniejsze

Pętla for-each jest szczególnie przydatna podczas iteracji nad zbiorem.

List<String> list = 
for(Iterator<String> iter = list.iterator(); list.hasNext(); ) {
    String s = list.next();

Jest łatwiejsza do napisania jako (ale robi to samo co, więc nie jest bardziej efektywna dla program)

List<String> list = 
for(String s: list) {

Używanie "starej" pętli jest nieco bardziej efektywne, gdy dostęp do losowo dostępnej kolekcji przez indeks.

List<String> list = new ArrayList<String>(); // implements RandomAccess
for(int i=0, len = list.size(); i < len; i++) // doesn't use an Iterator!

Używanie pętli for-each na zbiorze zawsze używa iteratora, który jest nieco mniej wydajny dla list dostępu losowego.

AFAIK, używanie pętli for-each nigdy nie jest bardziej efektywne dla programu, ale jak mówiłem, wydajność programisty jest często o wiele ważniejsza .

 7
Author: Peter Lawrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-19 07:03:52

For-each używa interfejsu iteratora. Wątpię, że jest bardziej wydajny niż" stary " styl. Iterator musi również sprawdzić rozmiar listy.

To głównie dla czytelności.

Powinno to być szybsze dla zbiorów bez dostępu losowego, takich jak LinkedList, ale wtedy porównanie jest niesprawiedliwe. I tak nie przywykłbyś do drugiej implementacji (z wolnym dostępem indeksowanym).

 3
Author: Thilo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-19 06:59:42

Pętla foreach jest tak efektywna jak tego typu pętla:

for (Iterator<Foo> it = list.iterator(); it.hasNext(); ) {
     Foo foo = it.next();
     ...
}
Ponieważ jest to ściśle równoważne.

Jeśli iterujesz przez Listę używając

int size = list.size();
for (int i = 0; i < size; i++) {
    Foo foo = list.get(i);
    ...
}

Wtedy pętla foreach będzie miała podobną wydajność jak twoja pętla, ale tylko dla ArrayList. W przypadku LinkedList, twoja pętla będzie miała fatalną wydajność, ponieważ w każdej iteratioon będzie musiała przemierzać wszystkie węzły listy, aż dotrze do iTH elementu.

Pętla foreach (lub pętla oparta na iteratorze, która jest taka sama), nie ma tego problemu, ponieważ iterator zachowuje odniesienie do bieżącego węzła i po prostu przechodzi do następnego przy każdej iteracji. Jest to wybór bast, ponieważ działa dobrze ze wszystkimi typami list. Jest również bardziej wyrazista i bezpieczniejsza, ponieważ nie ryzykujesz zwiększenia indeksu wewnątrz pętli lub użycia niewłaściwego indeksu w przypadku zagnieżdżonych pętli.

 3
Author: JB Nizet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-19 07:02:36

From Effective Java:

Standardowy idiom do zapętlania tablicy niekoniecznie skutkuje zbędne kontrole. Nowoczesne implementacje JVM optymalizują je.

Ale Josh Bloch nie opisuje jak JVM je optymalizuje.

 0
Author: Geek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-19 09:50:01

Wszystkie odpowiedzi są dobre i myślę, że więcej odpowiedzi nie jest potrzebnych, ale chcę tylko zaznaczyć, że:

Instrukcja enhanced for może być używana tylko do obtain array elements

Tonie może BYĆużywane do modify elements.

Jeśli twój program wymaga modyfikacji elementów, użyj tradycyjnego kontrolowanego for oświadczenie.

Spójrz

int[] array = { 1, 2, 3, 4, 5 };
for (int counter = 0; counter < array.length; counter++)
    array[counter] *= 2;

Nie możemy użyć enhanced for, Ponieważ jesteśmy modifying the array’s elements.

 0
Author: Basheer AL-MOMANI,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-30 08:49:56