Java 8: Difference between method reference Bound Receiver and UnBound Receiver

拈花ヽ惹草 提交于 2019-11-26 07:39:49

问题


I am trying to use Java 8 method references in my code. There are four types of method references available.

  1. Static method reference.
  2. Instance Method (Bound receiver).
  3. Instance Method (UnBound receiver).
  4. Constructor reference.

With Static method reference and Constructor reference i have no problem, but Instance Method (Bound receiver) and Instance Method (UnBound receiver) really confused me. In Bound receiver, we are using an Object reference variable for calling a method like:

objectRef::Instance Method

In UnBound receiver we are using Class name for calling a method like:

ClassName::Instance Method.

I have the following question:

  1. What is the need for different types of method references for Instance Methods?
  2. What is the difference between Bound and Unbound receiver method references?
  3. Where should we use Bound receiver and where should we use Unbound receiver?

I also found the explanation of Bound and Unbound receiver from Java 8 language features books, but was still confused with the actual concept.


回答1:


The idea of unBound receiver such as String::length is that you’re referring to a method to an object that will be supplied as one of the parameters of the lambda. 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

(arg0, rest) -> arg0.instanceMethod(rest) can be ClassName::instanceMethod (arg0 is of type ClassName)

(args) -> expr.instanceMethod(args) can be expr::instanceMethod

Answer retired from Java 8 in Action book




回答2:


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;
    }
}



回答3:


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().




回答4:


I've captured this from a recent presentation




回答5:


Along with the excellent answers from above. Thanks to the wonderful explanation by joshua bloch, effective java third edition. I was finally able to wrap my head around what bounded and unbounded reference means.

In bounded reference, the receiving object is specified in the method reference. Bound references are similar in nature to static references: the function object takes the same arguments as the referenced method.

In unbound references, the receiving object is specified when the function object is applied, via an additional parameter before the method’s declared parameters. Unbound references are often used as mapping and filter functions in stream pipelines

Finally, there are two kinds of constructor references, for classes and arrays. Constructor references serve as factory objects.

`Method Ref    |     Example                   |    Lambda Equivalent
  Static       |   Integer::parseInt           |   str -> Integer.parseInt(str)
  Bound        |   Instant.now()::isAfter      |   Instant then = Instant.now(); 
                                               |   t -> then.isAfter(t)
  Unbound      |  String::toLowerCase          |   str -> str.toLowerCase()
  Class 
Constructor    |  TreeMap<K,V>::new            |   () -> new TreeMap
  Array 
Constructor    |   int[]::new                  |  len -> new int[len]`



回答6:


Here's an example:

public static void main(String[] args) {
    // unbound
    UnaryOperator<String> u = String::toUpperCase;
    System.out.println(u.apply("hello"));

    // bound
    String a = "hello";
    Supplier<String> r = a::toUpperCase;
    System.out.println(r.get());
}

which will output two lines of HELLO.



来源:https://stackoverflow.com/questions/35914775/java-8-difference-between-method-reference-bound-receiver-and-unbound-receiver

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!