A Java lambda referencing an element from its enclosing scope holds a reference to its enclosing object. A contrived example, with lambda holding ref to MyClass:
class MyClass {
final String foo = "foo";
public Consumer<String> getFn() {
return bar -> System.out.println(bar + foo);
}
}
This is problematic if the lifetime of the lambda is long; then we've got a ref to MyClass that is long-lived, when it would have otherwise gone out of scope. Here we can optimize by replacing the lambda with a private static class, so that we're only holding a reference to the String we need rather than to the entire class:
class MyClass {
private static class PrintConsumer implements Consumer<String> {
String foo;
PrintConsumer(String foo) {
this.foo = foo;
}
@Override
public void accept(String bar) {
System.out.println(bar + foo);
}
}
final String foo = "foo";
public Consumer<String> getFn() {
return new PrintConsumer(foo);
}
}
Unfortunately this is super verbose and destroys the nice syntax we get from using (effectively final) variables from enclosing scope in lambdas. Is this technically optimal? Is there always a tradeoff here between nice syntax and the possibility of keeping a ref longer than necessary?
We can’t hide variables from the enclosing scope inside the lambda’s body. In this case, the keyword this is a reference to an enclosing instance. For example, in the class UseFoo, we have an instance variable value: Then in some method of this class, place the following code and execute this method:
Static Method References. A static method reference allows us to use a static method as a lambda expression. The static methods can be defined in a class, an interface, or an enum. The following code defines two lambda expressions. The first lambda expression func1 is created by defining an input parameter x and providing lambda expression body ...
Java Lambda - Java Static Method Reference. A lambda expression represents an anonymous function defined in a functional interface. A method reference creates a lambda expression using an existing method. Two consecutive colons act as a separator.
A static method reference allows us to use a static method as a lambda expression. The static methods can be defined in a class, an interface, or an enum.
class MyClass {
final String foo = "foo";
private Consumer<String> getFn() {
String localFoo = foo;
return bar -> System.out.println(bar + localFoo);
}
}
Now, the lambda only captures local variables inside of getFn()
. MyClass.this
is no longer captured.
class MyClass {
final String foo = "foo";
private Consumer<String> getFn() {
return getFn(foo);
}
private static Consumer<String> getFn(String localFoo) {
return bar -> System.out.println(bar + localFoo);
}
}
A combination of Lukas Eder's local-final-variable and helper-method-delegation solutions:
class MyClass {
final String foo = "foo";
private Consumer<String> getFn() {
return apply(
foo,
localFoo -> bar -> System.out.println(bar + localFoo)
);
}
private static <IN, OUT> OUT apply(
final IN in,
final Function<IN, OUT> function
) {
return function.apply(in);
}
}
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