Sposoby iteracji listy w Javie
Będąc nieco nowy w języku Java staram się zapoznać ze wszystkimi sposobami (a przynajmniej tymi Nie patologicznymi), które można iterować poprzez listę (lub być może inne kolekcje) oraz zaletami lub wadami każdego z nich.
Biorąc pod uwagę obiekt List<E> list
, znam następujące sposoby pętli przez wszystkie elementy:
Podstawowe dla loop (oczywiście istnieją równoważne while
/ do while
pętle również)
// 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: Jako @amarse
za iterację nad List
s, ponieważ rzeczywista implementacja
metoda get
może nie być tak skuteczna jak w przypadku stosowania metody Iterator
.
Na przykład, LinkedList
implementacje muszą przemierzać wszystkie
elementy poprzedzające i, aby uzyskać i-ten element.
W powyższym przykładzie nie ma możliwości implementacji List
do
"Zachowaj swoje miejsce", aby uczynić przyszłe iteracje bardziej wydajnymi.
Dla ArrayList
to naprawdę nie ma znaczenia, ponieważ złożoność / koszt get
jest stała czasu(O (1)), podczas gdy dla LinkedList
jest proporcjonalna do wielkości listy(O (n)).
Aby uzyskać więcej informacji na temat złożoności obliczeniowej wbudowanych implementacji Collections
, sprawdź to pytanie.
Enhanced for loop (ł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
// ...
}
Listysterator
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
// ...
}
Funkcjonalne Java
list.stream().map(e -> e + 1); // Can apply a transformation function for e
Iterable.forEach, strumień.forEach ,...
(metoda map z API strumienia Java 8 (Zobacz odpowiedź @i_am_zero).)
W Javie 8 klas kolekcji implementujących Iterable
(na przykład wszystkie List
s) mają teraz metodę forEach
, która może być używana zamiast instrukcji for loop 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 jakieś?
(BTW, moje zainteresowanie wcale nie wynika z chęci optymalizacji wydajności; chcę tylko wiedzieć, jakie formularze są dostępne dla mnie jako programisty.)
11 answers
[14]}trzy formy pętli są prawie identyczne. Rozszerzona pętla for
:
for (E element : list) {
. . .
}
Jest, zgodnie ze specyfikacją języka Java , identyczny w efekcie do jawnego użycia iteratora z tradycyjną pętlą for
. W trzecim przypadku można modyfikować zawartość listy tylko przez usunięcie bieżącego elementu, a następnie tylko wtedy, gdy odbywa się to za pomocą metody remove
samego iteratora. Dzięki iteracji opartej na indeksach możesz dowolnie modyfikować listę w dowolnym sposób. Jednak dodawanie lub usuwanie elementów przed bieżącym indeksem grozi, że Twoja pętla pominie elementy lub przetworzy ten sam element wiele razy; musisz odpowiednio dostosować indeks pętli podczas wprowadzania takich zmian.
We wszystkich przypadkach, element
jest odniesieniem do rzeczywistego elementu listy. Żadna z metod iteracji nie tworzy kopii czegokolwiek z listy. Zmiany stanu wewnętrznego element
będą zawsze widoczne w stanie wewnętrznym odpowiedniego elementu na lista.
Zasadniczo istnieją tylko dwa sposoby iteracji listy: używając indeksu lub używając iteratora. Pętla enhanced for jest tylko skrótem składniowym wprowadzonym w Javie 5, aby uniknąć nudy jawnego definiowania iteratora. Dla obu stylów można wymyślić zasadniczo trywialne odmiany za pomocą for
, while
albo do while
bloki, ale wszystkie sprowadzają się do tego samego (a raczej dwóch rzeczy).
EDIT: jak @iX3 wskazuje w komentarzu, możesz użyć ListIterator
, aby ustawić bieżący element listy w trakcie iteracji. Trzeba by użyć List#listIterator()
zamiast List#iterator()
aby zainicjalizować zmienną pętli (która oczywiście musiałaby być zadeklarowana jako ListIterator
, a nie Iterator
).
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
2013-12-15 21:01:52
Przykład każdego rodzaju wymienionego w pytaniu:
/ Align = "left" / javaimport java.util.*;
public class ListIterationExample {
public static void main(String []args){
List<Integer> numbers = new ArrayList<Integer>();
// populates list with initial values
for (Integer i : Arrays.asList(0,1,2,3,4,5,6,7))
numbers.add(i);
printList(numbers); // 0,1,2,3,4,5,6,7
// replaces each element with twice its value
for (int index=0; index < numbers.size(); index++) {
numbers.set(index, numbers.get(index)*2);
}
printList(numbers); // 0,2,4,6,8,10,12,14
// does nothing because list is not being changed
for (Integer number : numbers) {
number++; // number = new Integer(number+1);
}
printList(numbers); // 0,2,4,6,8,10,12,14
// same as above -- just different syntax
for (Iterator<Integer> iter = numbers.iterator(); iter.hasNext(); ) {
Integer number = iter.next();
number++;
}
printList(numbers); // 0,2,4,6,8,10,12,14
// ListIterator<?> provides an "add" method to insert elements
// between the current element and the cursor
for (ListIterator<Integer> iter = numbers.listIterator(); iter.hasNext(); ) {
Integer number = iter.next();
iter.add(number+1); // insert a number right before this
}
printList(numbers); // 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
// Iterator<?> provides a "remove" method to delete elements
// between the current element and the cursor
for (Iterator<Integer> iter = numbers.iterator(); iter.hasNext(); ) {
Integer number = iter.next();
if (number % 2 == 0) // if number is even
iter.remove(); // remove it from the collection
}
printList(numbers); // 1,3,5,7,9,11,13,15
// ListIterator<?> provides a "set" method to replace elements
for (ListIterator<Integer> iter = numbers.listIterator(); iter.hasNext(); ) {
Integer number = iter.next();
iter.set(number/2); // divide each element by 2
}
printList(numbers); // 0,1,2,3,4,5,6,7
}
public static void printList(List<Integer> numbers) {
StringBuilder sb = new StringBuilder();
for (Integer number : numbers) {
sb.append(number);
sb.append(",");
}
sb.deleteCharAt(sb.length()-1); // remove trailing comma
System.out.println(sb.toString());
}
}
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
2013-08-23 21:09:38
Pętla podstawowa nie jest zalecana, ponieważ nie znasz implementacji listy.
Jeśli to była LinkedList, każde wywołanie do
list.get(i)
Byłoby iteracją nad listą, co skutkowałoby złożonością czasową N^2.
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
2015-04-08 19:22:19
Iteracja w stylu JDK8:
public class IterationDemo {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3);
list.stream().forEach(elem -> System.out.println("element " + elem));
}
}
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-04-06 17:01:47
W Java 8 mamy wiele sposobów iteracji klas kolekcji.
Using Iterable forEach
Zbiory implementujące Iterable
(na przykład wszystkie listy) mają teraz metodę forEach
. Możemy użyć metody - reference wprowadzonej w Javie 8.
Arrays.asList(1,2,3,4).forEach(System.out::println);
Używanie strumieni forEach i forEachOrdered
Możemy również iterować nad listą używając Stream jako:
Arrays.asList(1,2,3,4).stream().forEach(System.out::println);
Arrays.asList(1,2,3,4).stream().forEachOrdered(System.out::println);
Powinniśmy preferować forEachOrdered
nad forEach
, ponieważ zachowanie forEach
jest jawnie nieeterministyczne, gdzie jako forEachOrdered
wykonuje akcję dla każdego elementu tego strumienia, w porządku spotkania strumienia, jeśli strumień ma zdefiniowany porządek spotkania. Tak więc forEach nie gwarantuje, że zamówienie zostanie zachowane.
Zaletą strumieni jest to, że możemy również korzystać z równoległych strumieni, gdzie jest to właściwe. Jeśli celem jest tylko wydrukowanie elementów niezależnie od kolejności, możemy użyć parallel stream jako:
Arrays.asList(1,2,3,4).parallelStream().forEach(System.out::println);
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
2018-02-25 02:08:09
Nie wiem, co uważasz za patologiczne, ale pozwól mi podać kilka alternatyw, których wcześniej nie widziałeś: {]}
List<E> sl= list ;
while( ! sl.empty() ) {
E element= sl.get(0) ;
.....
sl= sl.subList(1,sl.size());
}
Lub jego rekurencyjna wersja:
void visit(List<E> list) {
if( list.isEmpty() ) return;
E element= list.get(0) ;
....
visit(list.subList(1,list.size()));
}
Również rekurencyjna wersja klasycznego for(int i=0...
:
void visit(List<E> list,int pos) {
if( pos >= list.size() ) return;
E element= list.get(pos) ;
....
visit(list,pos+1);
}
Wspominam o nich, ponieważ jesteś "trochę nowy w Javie" i to może być interesujące.
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
2013-08-23 19:59:29
Możesz użyć forEach zaczynając od Java 8:
List<String> nameList = new ArrayList<>(
Arrays.asList("USA", "USSR", "UK"));
nameList.forEach((v) -> System.out.println(v));
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
2018-02-23 17:28:03
Do wyszukiwania wstecz powinieneś użyć następującego:
for (ListIterator<SomeClass> iterator = list.listIterator(list.size()); iterator.hasPrevious();) {
SomeClass item = iterator.previous();
...
item.remove(); // For instance.
}
Jeśli chcesz poznać pozycję, Użyj iteratora.previousIndex (). Pomaga również napisać wewnętrzną pętlę, która porównuje dwie pozycje na liście (Iteratory nie są sobie równe).
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
2016-11-25 13:12:18
W java 8
możesz użyć metody List.forEach()
z lambda expression
do iteracji listy.
import java.util.ArrayList;
import java.util.List;
public class TestA {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Apple");
list.add("Orange");
list.add("Banana");
list.forEach(
(name) -> {
System.out.println(name);
}
);
}
}
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
2018-09-06 13:34:26
Prawo, wiele alternatyw są wymienione. Najprostszym i najczystszym byłoby użycie rozszerzonej instrukcji for
, Jak Poniżej. {[3] } jest typu iteracyjnego.
for ( FormalParameter : Expression ) Statement
Na przykład, aby iterować, List
for (String str : ids) {
// Do something
}
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
2018-02-23 17:26:33
Zawsze możesz wyłączyć pierwszy i trzeci przykład za pomocą pętli while I trochę więcej kodu. Daje to przewagę możliwości użycia Do-while:
int i = 0;
do{
E element = list.get(i);
i++;
}
while (i < list.size());
Oczywiście, tego rodzaju rzeczy mogą spowodować wyjątek NullPointerException, jeśli lista.size() zwraca 0, ponieważ zawsze jest wykonywana co najmniej raz. To może być naprawione przez testowanie czy element jest null przed użyciem jego atrybutów / metod tho. Jednak o wiele prostsze i łatwiejsze jest użycie pętli for
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
2013-08-23 19:07:36