Als etwas neu in der Java-Sprache I & #39; m versuchen, mich mit allen Möglichkeiten (oder zumindest die nicht-pathologischen), dass man durch eine Liste (oder vielleicht andere Sammlungen) und die Vorteile oder Nachteile der einzelnen iterieren könnte vertraut zu machen.
Ausgehend von einem List
Objekt kenne ich die folgenden Möglichkeiten, eine Schleife durch alle Elemente zu ziehen:
while
/ do while
Schleifen)// 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
// ...
}
Anmerkung: Wie @amarseillan schon sagte, ist diese Form eine schlechte Wahl
für die Iteration über Listen
, weil die tatsächliche Implementierung der
Methode nicht so effizient ist wie bei der Verwendung eines Iterators
.
Zum Beispiel müssen LinkedList
-Implementierungen alle Elemente durchlaufen
Elemente vor i durchlaufen, um das i-te Element zu erhalten.
In dem obigen Beispiel gibt es keine Möglichkeit für die List
-Implementierung
ihre Position zu speichern, um zukünftige Iterationen effizienter zu machen.
Für eine "ArrayList" spielt das keine Rolle, da die Komplexität/Kosten von "get" konstant sind (O(1)), während sie bei einer "LinkedList" proportional zur Größe der Liste sind (O(n)).
Weitere Informationen über die Komplexität der eingebauten Collections
-Implementierungen finden Sie unter [diese Frage] (https://stackoverflow.com/questions/559839/big-o-summary-for-java-collections-framework-implementations).
for (E element : list) {
// 1 - can call methods of element
// ...
}
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
// ...
}
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
// ...
}
list.stream().map(e -> e + 1); // Can apply a transformation function for e
(Eine Map-Methode aus Java 8's Stream API (siehe @i_am_zero's Antwort).)
In Java 8 haben Auflistungsklassen, die Iterable
implementieren (z.B. alle List
s) nun eine forEach
-Methode, die anstelle der oben gezeigten [for-Schleifenanweisung][for-loop] verwendet werden kann. (Hier ist [eine andere Frage][java-8-foreach-comparison], die einen guten Vergleich bietet.)
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).
Welche anderen Möglichkeiten gibt es, wenn überhaupt?
(Mein Interesse rührt übrigens keineswegs von dem Wunsch her, die Leistung zu optimieren; ich möchte nur wissen, welche Möglichkeiten mir als Entwickler zur Verfügung stehen.
Beispiel für jede in der Frage aufgeführte Art:
import 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());
}
}
Ich weiß nicht, was Sie für pathologisch halten, aber lassen Sie mich einige Alternativen aufzeigen, die Sie vielleicht noch nicht gesehen haben:
List<E> sl= list ;
while( ! sl.empty() ) {
E element= sl.get(0) ;
.....
sl= sl.subList(1,sl.size());
}
Oder seine rekursive Version:
void visit(List<E> list) {
if( list.isEmpty() ) return;
E element= list.get(0) ;
....
visit(list.subList(1,list.size()));
}
Auch eine rekursive Version des klassischen 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);
}
Ich erwähne sie, weil Sie "etwas neu in Java" sind und dies interessant sein könnte.
Sie können das erste und das dritte Beispiel jederzeit durch eine while-Schleife und etwas mehr Code ersetzen. Dies hat den Vorteil, dass Sie die do-while-Schleife verwenden können:
int i = 0;
do{
E element = list.get(i);
i++;
}
while (i < list.size());
Natürlich kann dies zu einer NullPointerException führen, wenn list.size() 0 zurückgibt, da es immer mindestens einmal ausgeführt wird. Dies kann jedoch behoben werden, indem man prüft, ob das Element null ist, bevor man seine Attribute/Methoden verwendet. Dennoch ist es viel einfacher und leichter, die for-Schleife zu verwenden