2017-08-25 1 views
2

Ich habe eine Frage zu den aufgelösten Arten von Verfahren :: lambdas in Java 8.Warum ist es möglich, eine Methodenreferenz anstelle einer Konverterinstanz zu übergeben?

dieses Beispiel angewandten Methoden, die eine Liste von Objekten wandelt eine gegebene Feder-Core-Converter Implementierung mit:

public static <S, T> List<T> convertToList(Collection<? extends S> input, Converter<S, T> converter) { 
    List<T> results = new ArrayList<>(input != null ? input.size() : 0); 
    if (input != null && !input.isEmpty()) { 
     for (S element : input) { 
      results.add(converter.convert(element)); 
     } 
    } 

    return results; 
} 

Dann sagen, ich habe eine bestimmte Implementierung, BoatConverter:

public class BoatConverter implements Converter<Boat, BoatConverted> { 

    @Override 
    public BoatConverted convert(Boat boat) { 
     // ... 
    } 

} 

eine Möglichkeit, dies zu nennen ist:

ConversionHelper.convertToList(response.getBoats(), boatConverter) 

Allerdings stelle ich fest, dass die Java-Compiler (und erwartete Ergebnisse) mit dieser ebenso glücklich sind:

ConversionHelper.convertToList(response.getBoats(), boatConverter::convert) 

Bei convert() in diesem Fall gibt eine BoatConverted, aber convertToList() ist ein Konverter Typ erwartet , meine Frage ist, wie der Compiler diese offensichtliche Kollision auflöst, zumal Sie ein Lambda von convert() übergeben, aber die convertToList() - Methode diese Methode auf einem erwarteten konvertierten Objekt aufrufen will?

+1

'Converter' ist eine funktionale Schnittstelle. –

Antwort

4

Converter ist effektiv eine funktionale Schnittstelle, da es nur eine einzige abstrakte Methode enthält:

package org.springframework.core.convert.converter; 

public interface Converter<S, T> { 
    T convert(S var1); 
} 

was bedeutet, dass sie als Ziel für die Lambda-Ausdrücke und Ihr Beispiel umgeschrieben werden könnte verwendet werden können:

c -> boatConverter.convert(c) 

In diesem Fall delegiert Ihr Lambda den Job einfach an die bereits vorhandene Instanz Converter, und da die Methodensignatur mit der Schnittstellenmethode übereinstimmt, ist es möglich, sie durch ein Meth zu ersetzen od Referenz.

Der wesentliche Unterschied besteht darin, dass, wenn Sie boatConverter sind vorbei, Sie sind einfach diese Instanz als Converter Wiederverwendung, aber wenn Sie boatConverter::convert schreiben oder c -> boatConverter.convert(c) Sie eine neue Converter Instanz, dass die Delegierten die Umstellung auf boatConverter

2

Grundsätzlich dass Konverter ist eigentlich das Gleiche wie Function (transformiert von einem Typ zum anderen) und es ist ein @FunctionalInterface - da es eine einzige abstrakte Methode hat.

Das ist der Grund, warum der Compiler das vollkommen in Ordnung bringen kann. Betrachten Sie dieses einfacheres Beispiel (IMO):

static class ToUpperCase implements Function<String, String> { 

    @Override 
    public String apply(String s) { 
     return s.toUpperCase(); 
    } 

} 

private static List<String> transformList(List<String> input, Function<String, String> f) { 
    return input.stream().map(f).collect(Collectors.toList()); 
} 

Diese beiden Anrufe funktionieren würde:

transformList(list, func); 
transformList(list, func::apply); 

Aber auch könnte die zweite geschrieben werden viel mehr klar:

transformList(list, String::toUpperCase); 

Als solches Ihrem Beispiel könnte klarer gemacht werden:

ConversionHelper.convertToList(response.getBoats(), Boat::getYourField) 

getYourField sollte offensichtlich mit was auch immer Sie tun ersetzt werden.Ich finde das viel ausführlicher, da es eine klare Aussage macht, dass Sie von Boot zu einigen seiner Felder umwandeln.

Verwandte Themen