Anonyme Methode in einer ForEach-Schleife

laudatio

Neues Mitglied
Soweit ich das verstanden habe, kann man Methoden als Implementierungen für funktionale Interfaces benutzen.Einzige Bedingung ist, dass der Methodenkörper übereinstimmt.

Wieso klappt dann folgendes?:

List<String> liste = Arrays.asList("qw", "eeqwe", "wdasd");
StringBuilder builder = new StringBuilder();

liste.forEach(builder::append);


Die ForEach-Schleife einer Liste verlange eine Implementation vom Consumer-Interface dessen accept()-Methode void ist und genau einen Parameter besitzt.

Die append-Methode des StringBuilders ist nicht void und gibt einen StringBuilder zurück.

Die Methodekörper sind hier doch anders.

Also wieso klappt das?
 
Vermutlich muss nur die Parameter-Liste übereinstimmen. Der Rückgabetyp wird ja eh nicht verwendet.

Im Hintergrund scheint viel "Magie" im Spiel zu sein. Siehe:
https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
Each functional interface has a single abstract method, called the functional method for that functional interface, to which the lambda expression's parameter and return types are matched or adapted.

und: http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#target-typing
oh und vorallem: http://cr.openjdk.java.net/~dlsmith/jsr335-0.6.1/E.html

If the body of a lambda is a statement expression (that is, an expression that would be allowed to stand alone as a statement), it is compatible with a void-producing functional interface type; any result is simply discarded. So, for example, both of the following are legal:

// Predicate has a boolean return
Predicate<String> p = s -> list.add(s);
// Block has a void return
Block<String> b = s -> list.add(s);

Generally speaking, a lambda of the form () -> expr, where expr is a statement expression, is interpreted as either () -> { return expr; } or () -> { expr; }, depending on the target type.
 
"Übereinstimmt" heißt bei Methoden natürlich immer, dass die Parameter-Typen der Lambda-Funktion Oberklassen sein müssen, und der Rückgabetyp eine Unterklasse (also eine Spezialisierung). So gesehen ist StringBuilder eine Unterklasse bzw. eine Spezialisierung von void. Ein StringBuilder hat alle Eigenschaften von 'void'.
Technisch gesehen spricht natürlich nichts dagegen. Du kannst die 'append'-Methode ja auch aufrufen, ohne den Rückgabewert zu benutzen:
Java:
StringBuilder builder = new StringBuilder();
builder.append("Foo")
lg Kevin
 

Zurück
Oben