Java 8: Difference between method reference Bound Receiver and UnBound Receiver
The idea of the unBound receiver such as String::length
is you're referring to a
method of an object that will be supplied as one of the lambda's parameters. For example,
the lambda expression (String s) -> s.toUpperCase()
can be rewritten as String::toUpperCase
.
But Bounded refers to a situation when you’re calling a method in a
lambda to an external object that already exists. For example, the lambda expression () -> expensiveTransaction.getValue()
can be rewritten as expensiveTransaction::getValue
.
Situations for three different ways of method reference
(args) -> ClassName.staticMethod(args)
can be ClassName::staticMethod
// This is static (you can think as unBound also)
(arg0, rest) -> arg0.instanceMethod(rest)
can be ClassName::instanceMethod
(arg0
is of type ClassName
) // This is unBound
(args) -> expr.instanceMethod(args)
can be expr::instanceMethod
// This is Bound
Answer retrieved from Java 8 in Action book
When you want the method to be executed for a specific instance of some class, you use a bound receiver.
For example :
Stream.of("x","y").forEach(System.out::println);
will execute println
on a sepcific instance of PrintStream
- the System.out
instance. Therefore System.out.println("x")
and System.out.println("y")
will be executed as a result of passing that method reference to forEach
.
On the other hand, if you want the method to be executed for an unspecified instance of a class, you can use a unbound receiver.
For example :
Stream.of("x","y","").filter(String::isEmpty);
will execute isEmpty()
on each of the String
instances of the Stream - i.e. "x".isEmpty()
, "y".isEmpty()
and "".isEmpty()
.
Basically, unbound receivers allow you to use instance methods as if they were static methods with a first parameter of the declaring type - so you can use them as functions by passing in whatever instance you want. With a bound receiver, the "target" instance is effectively part of the function.
An example might make this clearer:
import java.util.function.*;
public class Test {
private final String name;
public Test(String name) {
this.name = name;
}
public static void main(String[] args) {
Test t1 = new Test("t1");
Test t2 = new Test("t2");
Supplier<String> supplier = t2::method;
Function<Test, String> function = Test::method;
// No need to say which instance to call it on -
// the supplier is bound to t2
System.out.println(supplier.get());
// The function is unbound, so you need to specify
// which instance to call it on
System.out.println(function.apply(t1));
System.out.println(function.apply(t2));
}
public String method() {
return name;
}
}