Ich spiele mit Java 8 herum, um herauszufinden, wie es als erstklassige Bürger funktioniert. Ich habe das folgende Snippet:
package test;
import java.util.*;
import java.util.function.*;
public class Test {
public static void myForEach(List<Integer> list, Function<Integer, Void> myFunction) {
list.forEach(functionToBlock(myFunction));
}
public static void displayInt(Integer i) {
System.out.println(i);
}
public static void main(String[] args) {
List<Integer> theList = new ArrayList<>();
theList.add(1);
theList.add(2);
theList.add(3);
theList.add(4);
theList.add(5);
theList.add(6);
myForEach(theList, Test::displayInt);
}
}
Ich versuche, Methode displayInt
an Methode unter myForEach
Verwendung einer Methodenreferenz zu übergeben. Der Compiler erzeugt den folgenden Fehler:
src/test/Test.java:9: error: cannot find symbol
list.forEach(functionToBlock(myFunction));
^
symbol: method functionToBlock(Function<Integer,Void>)
location: class Test
src/test/Test.java:25: error: method myForEach in class Test cannot be applied to given ty
pes;
myForEach(theList, Test::displayInt);
^
required: List<Integer>,Function<Integer,Void>
found: List<Integer>,Test::displayInt
reason: argument mismatch; bad return type in method reference
void cannot be converted to Void
Der Compiler beschwert sich darüber void cannot be converted to Void
. Ich weiß nicht, wie ich den Typ der Funktionsschnittstelle in der Signatur angeben soll myForEach
, damit der Code kompiliert wird. Ich weiß , ich könnte einfach den Rückgabetyp ändern von displayInt
zu Void
und dann zurück null
. Es kann jedoch Situationen geben, in denen es nicht möglich ist, die Methode zu ändern, die ich an eine andere Stelle übergeben möchte. Gibt es eine einfache Möglichkeit zur Wiederverwendung displayInt
?
Block
wurde fürConsumer
in den neuesten Versionen der JDK 8 API geändertMethodHandle
). Auf diese Weise kann der Java-Compiler effizienteren Code erstellen, z. B. Lambdas ohne Abschluss als statische Methoden implementieren und so die Generierung von Methoden verhindern zusätzliche Klassen.Function<Void, Void>
istRunnable
.Runnable
undCallable
Schnittstellen steht geschrieben, dass sie in Verbindung mit Threads verwendet werden sollen . Die ärgerliche Folge davon ist, dass sich einige statische Analysewerkzeuge (wie Sonar) beschweren, wenn Sie dierun()
Methode direkt aufrufen .Wenn Sie eine Funktion als Argument akzeptieren müssen, das keine Argumente akzeptiert und kein Ergebnis zurückgibt (void), ist es meiner Meinung nach immer noch am besten, so etwas zu haben
irgendwo in deinem Code. In meinen funktionalen Programmierkursen wurde das Wort "Thunk" verwendet, um solche Funktionen zu beschreiben. Warum es nicht in java.util.function ist, kann ich nicht verstehen.
In anderen Fällen stelle ich fest, dass selbst wenn java.util.function etwas hat, das mit der gewünschten Signatur übereinstimmt, es sich immer noch nicht richtig anfühlt, wenn die Benennung der Schnittstelle nicht mit der Verwendung der Funktion in meinem Code übereinstimmt. Ich denke, es ist ein ähnlicher Punkt, der an anderer Stelle in Bezug auf 'Runnable' angesprochen wird - ein Begriff, der mit der Thread-Klasse assoziiert ist -, obwohl er möglicherweise die Signatur hat, die ich brauche, ist es dennoch wahrscheinlich, dass er den Leser verwirrt.
quelle
Runnable
keine geprüften Ausnahmen zulässig, sodass sie für viele Anwendungen unbrauchbar sind. Da dies auchCallable<Void>
nicht nützlich ist, müssen Sie anscheinend Ihre eigenen definieren. Hässlich.Setzen Sie den Rückgabetyp auf
Void
anstelle vonvoid
undreturn null
ODER
quelle
Ich denke, Sie sollten stattdessen die Consumer-Oberfläche verwenden
Function<T, R>
.Ein Consumer ist im Grunde eine funktionale Schnittstelle, die einen Wert akzeptiert und nichts zurückgibt (dh nichtig).
In Ihrem Fall können Sie einen Verbraucher an einer anderen Stelle in Ihrem Code wie folgt erstellen:
Dann können Sie Ihren
myForEach
Code durch das folgende Snippet ersetzen :Sie behandeln myFunction als erstklassiges Objekt.
quelle