Generische Methode zum Ausführen einer Map-Reduce-Operation. (Java-8)

8

Wie überladen Sie eine Funktion mit generischen Parametern in Java 8?

%Vor%
  

Fehler: Java: Namenskonflikt:   sum (java.util.function.Function & lt; T, java.lang.Double & gt;) und   sum (java.util.function.Function & lt; T, java.lang.Integer & gt;) haben die gleiche Löschung

    
Keisuke KATO 14.06.2015, 06:47
quelle

3 Antworten

3

Das Beispiel, das Sie in Ihrer Frage präsentieren, hat nichts mit Java 8 und allem, was mit der Funktionsweise von Generika in Java zu tun hat, zu tun. Function<T, Integer> function und Function<T, Double> function durchlaufen type-löschen , wenn sie kompiliert werden und werden in Function umgewandelt. Als Faustregel für das Überladen von Methoden gilt die unterschiedliche Anzahl, Art oder Reihenfolge der Parameter. Da beide Methoden transformiert werden, um ein Function Argument zu verwenden, beschwert sich der Compiler darüber.

srborlongan hat bereits eine Möglichkeit zur Lösung des Problems bereitgestellt. Das Problem mit dieser Lösung besteht darin, dass Sie Ihre Test -Klasse für jeden Operationstyp (Addition, Subtraktion usw.) auf verschiedenen Typen (Integer, Double usw.) ändern müssen. Eine alternative Lösung wäre die Verwendung von method overriding anstelle von method overloading :

Ändern Sie die Klasse Test wie folgt:

%Vor%

Erstellen Sie eine Unterklasse von Test , die zwei Integer s hinzufügt.

%Vor%

Der Clientcode kann dann den obigen Code wie folgt verwenden:

%Vor%

Der Vorteil dieses Ansatzes besteht darin, dass Ihre Test -Klasse mit dem open-closed -Prinzip übereinstimmt. Um eine neue Operation wie Multiplikation hinzuzufügen, müssen Sie lediglich eine neue Unterklasse von Test und override die Methode operation hinzufügen, um zwei Zahlen zu multiplizieren. Vereinbaren Sie dies mit dem Muster Decorator und Sie können sogar die Anzahl der Unterklassen minimieren, die Sie haben erstellen.

Hinweis Das Beispiel in dieser Antwort ist bezeichnend. Es gibt viele Bereiche der Verbesserung (wie make Test eine funktionale Schnittstelle anstelle einer abstrakten Klasse), die den Rahmen der Frage überschreiten.

    
CKing 14.06.2015, 07:57
quelle
6

Benji Weber schrieb einmal über ein Möglichkeit, dies zu umgehen. Sie müssen benutzerdefinierte Funktionsschnittstellen definieren, die die Typen für Ihre Parameter erweitern:

%Vor%

Eine andere Möglichkeit besteht darin, stattdessen java.util.function.ToIntFunction und java.util.function.ToDoubleFunction zu verwenden:

%Vor%     
srborlongan 14.06.2015 07:19
quelle
0

@srborlongans Lösung wird nicht sehr gut funktionieren:)

Siehe ein ähnliches Beispiel - Vergleicher -Methoden - comparingDouble(ToDoubleFunction) , comparingInt(ToIntFunction) , etc. Die Methoden haben unterschiedliche Namen, da Überladen hier keine gute Idee ist.

Der Grund dafür ist, dass der Compiler, wenn Sie sum(t->{...}) ausführen, nicht feststellen kann, welche Methode aufgerufen werden soll. Tatsächlich muss das Verfahren zuerst überladen werden, um eine Methode auszuwählen, bevor der Typ des impliziten Lambda-Ausdrucks (basierend auf der Signatur dieser Methode) abgeleitet wird.

Das ist enttäuschend. In der früheren Phase hatte Java8 eine komplexere Inferenz-Engine, und Comparator hatte comparing() Methoden überladen. und sum(t->{...}) würde ebenfalls korrekt abgeleitet werden. Leider haben sie sich einfach dazu entschieden :( Und hier sind wir jetzt.

Faustregel für das Überladen von Methoden mit funktionalen Argumenten: Die Aritäten der funktionalen Schnittstellen müssen unterschiedlich sein, es sei denn beide sind 0.

%Vor%

Der Grund, warum das Überladen mit arity 0 in Ordnung ist, ist, dass die Lambda-Ausdrücke nicht implizit sind - alle Argumenttypen sind bekannt (weil es kein Argument gibt!), wir benötigen keine kontextuellen Informationen für den Lambda-Typ

%Vor%     
ZhongYu 14.06.2015 15:41
quelle