Funktionsobjekte
Eine zentrale Idee der funktionale Programmierung ist, dass Funktionen Werte sind. Das bedeutet, dass Funktionen in Variablen gespeichert werden können. Dies ermöglicht es, Funktionen an Methoden als Parameter zu übergeben und auch aus Methoden Funktionen zurückgegeben. In objektorientierte Programmiersprachen wie Java, können wir dies simulieren, indem wir Funktionen als Objekte repräsentieren.
Dazu definieren wir uns ein Interface Function
, welches zwei Typparameter, T
und R
nutzt.
T
entspricht dabei dem Typ der Eingabe, und R
dem Typ des Rückgabewerts.
Das folgende Interface bildet also Funktionen ab:
interface Function<T, R> {
R apply(T x);
}
Die Methode apply
entspricht dem eigentlichen Funktionsaufruf.
Eine Funktion square
, könnte wie folgt implementiert werden:
class SquareFunction implements Function<Integer, Integer> {
public Integer apply(Integer x) {
return x * x;
}
}
Eine Funktion Cube
würde der folgenden Implementation entsprechen
class CubicFunction implements Function<Integer, Integer> {
public Integer apply(Integer x) {
return x * x * x;
}
}
Objekte dieser Funktionen können nun an Methoden übergeben werden:
class FunTest {
static int valueAtX (Function<Integer, Integer> fun, Integer x) {
return fun.apply(x);
}
public static void main(String[] args) {
int squareOf2 = valueAtX(new SquareFunction(), 2);
int cubeOf2 = valueAtX(new CubicFunction(), 2);
}
}
Genauso einfach können wir auch Funktionen aus Methoden zurückgeben. Angenommen, wir hätten eine allgemeine Klasse, welche die n-te Potenz berechnet:
class PowerFunction implements Function<Integer, Integer> {
int n = 0;
public PowerFunction(int n) {
this.n = n;
}
public Integer apply(Integer x) {
int pow = 1;
for (int i = 0; i < n; i = i + 1) {
pow = pow * x;
}
return pow;
}
}
Wir können nun eine Funktion schreiben, welche die Potenz n
als Argument entgegennimmt.
Ausgehend davon soll dann eine neue Funktion zurückgegeben werden, welche die n-te Potenz berechnet:
class FunTest {
static Function<Integer, Integer> nthPower (int n) {
return new PowerFunction(n);
}
}
Zugegeben: Diese Beispiele sind nicht sehr nützlich. Wir könnten all diese Berechnungen viel einfacher schreiben, indem wir auf diese Funktionsklassen verzichten. Diese Beispiele dienen nur dazu zu illustrieren, dass wir Funktionen mittels Objekten simulieren können. Dies ist tatsächlich auch der Weg, den Java eingeschlagen hat. Java stellt uns jedoch mit Lambda-Ausdrücken eine spezielle Syntax zur Verfügung. Mit diesem können wir solche Funktionsobjekte schreiben, ohne jedes Mal eine Klasse schreiben zu müssen.
Experimente
- Können Sie Funktionen schreiben, die nicht nur Integer, sondern auch Double Werte zurückgeben? Wie ist es mit String?
- Schreiben Sie ein Interface
Function2<T, V, R>
welche eine Funktion mit zwei Argumenten repräsentiert. Implementieren Sie dann die Funktionenplus
undminus
, wobei Sie fürT
undV
den TypDouble
wählen.
Haben Sie Fragen oder Bemerkungen? Schreiben Sie diese doch ins Forum.