Będąc nieco nowym językiem Java, próbuję zapoznać się ze wszystkimi sposobami (a przynajmniej niepatologicznymi), które można iterować po liście (lub innych kolekcjach) oraz zaletami i wadami każdego z nich.
Biorąc pod uwagę List<E> listobiekt, znam następujące sposoby przechodzenia przez wszystkie elementy:
Podstawowy dla pętli (oczywiście istnieją również odpowiedniki while/ do whilepętle)
// Not recommended (see below)!
for (int i = 0; i < list.size(); i++) {
E element = list.get(i);
// 1 - can call methods of element
// 2 - can use 'i' to make index-based calls to methods of list
// ...
}
Uwaga: Jak zauważył @amarseillan, ta forma jest kiepskim wyborem dla iteracji w porównaniu z Lists, ponieważ faktyczna implementacja getmetody może nie być tak wydajna jak w przypadku korzystania z Iterator. Na przykład LinkedListimplementacje muszą przechodzić przez wszystkie elementy poprzedzające i, aby uzyskać i-ty element.
W powyższym przykładzie Listimplementacja nie może „zapisać swojego miejsca”, aby zwiększyć wydajność przyszłych iteracji. Dla a ArrayListtak naprawdę nie ma to znaczenia, ponieważ złożoność / koszt getto stały czas (O (1)), podczas gdy dla a LinkedListjest proporcjonalny do wielkości listy (O (n)).
Aby uzyskać więcej informacji na temat złożoności obliczeniowej wbudowanych Collectionsimplementacji, sprawdź to pytanie .
Ulepszone dla pętli (ładnie wyjaśnione w tym pytaniu )
for (E element : list) {
// 1 - can call methods of element
// ...
}
Iterator
for (Iterator<E> iter = list.iterator(); iter.hasNext(); ) {
E element = iter.next();
// 1 - can call methods of element
// 2 - can use iter.remove() to remove the current element from the list
// ...
}
ListIterator
for (ListIterator<E> iter = list.listIterator(); iter.hasNext(); ) {
E element = iter.next();
// 1 - can call methods of element
// 2 - can use iter.remove() to remove the current element from the list
// 3 - can use iter.add(...) to insert a new element into the list
// between element and iter->next()
// 4 - can use iter.set(...) to replace the current element
// ...
}
Funkcjonalna Java
list.stream().map(e -> e + 1); // Can apply a transformation function for e
Iterable.forEach , Stream.forEach ...
(Metoda mapy z Stream API Java 8 (patrz odpowiedź @ i_am_zero).)
W klasach Java 8, które implementują Iterable(na przykład wszystkie Lists), istnieje teraz forEachmetoda, której można użyć zamiast instrukcji pętli for pokazanej powyżej. (Oto kolejne pytanie, które zapewnia dobre porównanie).
Arrays.asList(1,2,3,4).forEach(System.out::println);
// 1 - can call methods of an element
// 2 - would need reference to containing object to remove an item
// (TODO: someone please confirm / deny this)
// 3 - functionally separates iteration from the action
// being performed with each item.
Arrays.asList(1,2,3,4).stream().forEach(System.out::println);
// Same capabilities as above plus potentially greater
// utilization of parallelism
// (caution: consequently, order of execution is not guaranteed,
// see [Stream.forEachOrdered][stream-foreach-ordered] for more
// information about this).
Jakie są inne sposoby, jeśli istnieją?
(BTW, moje zainteresowanie wcale nie wynika z chęci optymalizacji wydajności ; chcę tylko wiedzieć, jakie formy są dostępne jako programista).
Listinterfejsu jest specyficzne?