2016-06-25 8 views
2

Meine Frage betrifft die Java foreach-Schleife, eingeführt in Java 5 und Iterable.forEach(), in Java eingeführt 8.Ist der Ersatz einer foreach-Schleife durch Iterable.forEach rein kosmetisch?

Lassen Sie uns sagen, dass ein Programm mit einer Liste der String-Werte vorhanden ist, und die Funktion des Programms ist über iterieren jede einzelne Zeichenfolge und verwenden Sie es als Methodenparameter.

Ein solches Programm wie dieses, wie von Java aussehen könnte 5:

for (String s : stringList) { 
    doSomething(s); 
} 

jedoch mit der Einführung von Iterable.forEach() in Java 8, ein solches Programm könnte wie folgt aussehen:

stringList.forEach(this::doSomething); 

Meine Frage ist, gibt es einen Grund, Iterable.forEach() anstatt der foreach-Schleife jenseits der Einsparung von ein paar Zeilen zu verwenden?

+2

Wenn 'doSomething' eine geprüfte Ausnahme wirft, Sie dann fangen sie explizit ... müssen – Tunaki

+0

@Tunaki Es kann nicht klar gewesen, aber ich meinte implizieren Das ist eine sichere Methode ohne Ausnahmen. – GingerDeadshot

+0

Es macht mehr Unterschied, wenn Sie einen parallelen Strom verwenden. –

Antwort

5

Die Bereitstellung einer forEach macht die Aktion auf die Elemente steckbar und sehr flexibel durchgeführt werden. Es kann ein direktes Lambda, ein MethodHandle oder sogar ein MethodHanlde sein, das dynamisch aus einem statischen Teil des Verhaltens und einem von der Laufzeit definierten Teil davon zusammengesetzt ist. Intern kann die Erstellung eines expliziten Iterator Objekts vermieden werden. Ansonsten können Sie natürlich das gleiche Verhalten durch eine externe Schleife simulieren. Das sieht vielleicht nicht so gut aus.

+0

Ausgezeichnete Antwort und genau das, was ich mir erhofft hatte. – GingerDeadshot

+2

@Deadshot Es hat auch einige signifikante Einschränkungen im Vergleich zur for-each-Schleife. Sie können den nichtlokalen Kontrollfluss (break/continue) nicht aus der Aktion heraus verwenden. Sie können nicht auf änderbare lokale Benutzer zugreifen; und Sie können geprüfte Ausnahmen auch dann nicht auslösen, wenn die umschließende Methode sie deklariert. Das eine ersetzt das andere nicht. –

2

In der neuen Java8 API Sie Dinge wie

stringList.stream().filter(...).map(...).forEach(...) 

tun können, die oft anfällig sauberer und weniger Fehler sein kann, als nur für Schleife für jeden innerhalb eines die gleiche transformationsize und Filterung zu tun.

+4

Große Antwort, aber nicht unbedingt für diese Frage. – GingerDeadshot

3

Der grundlegende Vorteil besteht darin, dass die interne Iteration, die Sie mit forEach sollte die Bibliothek, es zu tun entscheiden, nutzen können. Wenn Sie die erweiterte for-Schleife (for x : xs) verwenden, bestehen Sie auf externe Iteration.

Die Idee ist, dass Sie wollen, dass eine Funktion jedes Element einer Liste (oder Iterable) nimmt und etwas damit macht. Das nicht-funktionale (traditionell in Java) ist es, über die Liste in Ihrem Code zu iterieren und es zu tun. Dies wird externe Iteration genannt. Dies erzwingt eine sequenzielle Ausführung.

Mit Java 8 können Sie Lambda-Ausdruck erstellen und übergeben. Sie übergeben also das Verhalten oder die Funktion, die das Element akzeptiert. Sie verzichten also auf die Kontrolle über die Iteration und lassen die Listenimplementierung (sozusagen Bibliothekscode) sich um Iteration kümmern und möglicherweise die Bemühungen parallelisieren.

+0

Interessant. [Der Vertrag] (http://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html#forEach-java.util.function.Consumer-) erlaubt in der Tat andere Aufträge, wenn sie dokumentiert sind . –

5

Hier sind 3 Unterschiede zwischen den beiden zu berücksichtigen:

  • Lambdas nicht nicht-final Variablen erfassen kann.

  • Eine forEach lässt break/continue nicht zu.

  • Geprüfte Ausnahmen müssen abgefangen werden innerhalb ein bestandener Lambda (seit der Typ ist Consumer<...>).

List<MyClass> list = ...; 

MyClass mc = null; 

for(MyClass e : list) { 
    if(e.test("bla")) { 
     mc = e; 
     break; 
    } 
}    

list.forEach(e -> { 
    if(e.test("bla")) { 
     mc = e; // Does not compile 
     break; // Also, does not compile 
    } 
}); 
void method() throws Exception {   
    ... 
    for(MyClass e : list) { 
     ... 
     throw new Exception("Oops"); 
    } 

    list.forEach(e -> { 
     ... 
     throw new Exception("Oops"); // Error: unhandled exception 
    }); 
} 
+2

Sie haben auch vergessen: Überprüfte Ausnahmen (auch wenn die umschließende Methode deklariert wurde, sie zu werfen). –

+1

@BrianGoetz Danke, ich habe ein Beispiel hinzugefügt :) –

Verwandte Themen