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
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:
Erstellen Sie eine Unterklasse von Test
, die zwei Integer
s hinzufügt.
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.
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%@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%Tags und Links java java-8 generics function overloading