I have a good understanding about lambda functions in Lisp. Java seems not to have the same flexibility as Lisp. How do I have to think about lambdas in Java? Given the code below, how can I do that?
public class Draw {
GraphicsContext gc;
static void draw(double x, double y, double w, double h, boolean drawRect) {
if (drawRect) {
gc.fillRect(x, y, w, h);
} else {
gc.strokeRect(x, y, w, h);
}
}
// How do I do that?
static void drawWithLambda(double x, double y, double w, double h /**, lambda */) {
lambda(x, y, w, h);
}
public static void main(String[] args) {
draw(0, 0, 50, 50, false); // OK
drawWithLambda(0, 0, 50, 50, GraphicsContext::fillRect); // Ok?
}
}
Lambda in Java work in combination with the notion of functional interface.
The typical example is Function
. Function
is an functional interface whose functional method, apply
, is a method that takes a single argument and return a result.
You can create your own functional interface, who would define a functional method taking 4 parameters and having no return type, like this:
@FunctionalInterface
interface RectangleDrawer {
void draw(double x, double y, double w, double h);
}
(The FunctionalInterface
annotation is not strictly necessary but it gives a clear intent).
You can then create a lambda that comply with the contract of this functional interface. The typical lambda syntax is (method arguments) -> (lambda body)
. In this example, it would be: (x, y, w, h) -> gc.fillRect(x, y, w, h)
. This compiles because the lambda declares 4 arguments and has no return type, so it can be represented as the functional method of RectangleDrawer
defined before.
You example would become:
static GraphicsContext gc;
public static void main(String[] args) {
draw(0, 0, 50, 50, (x, y, w, h) -> gc.fillRect(x, y, w, h));
draw(0, 0, 50, 50, (x, y, w, h) -> gc.strokeRect(x, y, w, h));
}
static void draw(double x, double y, double w, double h, RectangleDrawer drawer) {
drawer.draw(x, y, w, h);
}
In this particular case, it is possible to use a method reference to create the lambda, using the ::
operator, which allows to write simpler code:
static GraphicsContext gc;
public static void main(String[] args) {
draw(0, 0, 50, 50, gc::fillRect);
draw(0, 0, 50, 50, gc::strokeRect);
}
static void draw(double x, double y, double w, double h, RectangleDrawer drawer) {
drawer.draw(x, y, w, h);
}
You must specify the type of a functional interface that the lambda
method argument implements :
drawWithLambda(double x, double y, double w, double h, SomeFuncInterface lambda) {
lambda.someMethod (x, y, w, h); // someMethod is the single method that
// SomeFuncInterface implements
}
In order for this line to work
drawWithLambda(0, 0, 50, 50, GraphicsContext::fillRect);
the method fillRect
of GraphicsContext
must be compatible with the signature of the method of the SomeFuncInterface
functional interface.
BTW, GraphicsContext::fillRect
is a method reference, not a lambda expression. You can pass either lambda expressions, method references or any other implementation of the functional interface (regular class instance, anonymous class instance, etc...).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With