Method reference in Java 8

前端 未结 5 1003
梦如初夏
梦如初夏 2021-02-13 15:31
public class Car {

    private int maxSpeed;

    public Car(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    public int getMaxSpeed() {
        return maxS         


        
相关标签:
5条回答
  • 2021-02-13 16:15

    A member function with no parameters actually has a hidden parameter, the this reference. Method references of the form ClassName::memberFunction always use the first parameter of the functional type for the class instance, i.e. the instance's hidden this parameter. So, in the case of Car.getMaxSpeed(), internally it has the same parameters as a static Integer getMaxSpeed(Car car). Car::getMaxSpeed would therefore fit the functional type Function<Car,Integer>, just as a static Integer getMaxSpeed(Car car) would.

    Something similar happens with member functions that take one parameter--they fit the BiFunction functional type, with the first parameter being the class instance.

    0 讨论(0)
  • 2021-02-13 16:22

    Let's look at Function in detail:

    Interface Function<T,R> {
    
        default <V> Function<T,V>   andThen(Function<? super R,? extends V> after){}
    
        R   apply(T t);
    
        default <V> Function<V,R>   compose(Function<? super V,? extends T> before){}
    
        static <T> Function<T,T>    identity();
    
    }
    

    note the R apply(T t); Applies this function to the given argument.

    Function<Void, Integer> function = Void::?????;
    Void voidInstance = null;
    function.apply(voidInstance);
    

    This doesn't make sense. You want to pass a Void so that the function of the Void is applied ?

    A few illustrative examples of what compiles as a function

    note that c->c.getMaxSpeed() and Car::getMaxSpeed are syntactically equivalent if the method is an instanceMethod. For non-static-methods the first argument is infered from the type who's method is used, and needs to be provided later (as the instance which the method will be executed on/applied on).

    public class Car {
    
        private int maxSpeed;
    
        public Car(int maxSpeed) {
            this.maxSpeed = maxSpeed;
        }
    
        public int getMaxSpeed() {
            return this.maxSpeed;
        }
        public Void setMaxSpeed() {
            this.maxSpeed = 12;
            return null;
        }
        public static int intStaticFunction(Void v) {
            return new Random().nextInt();
        }
        public static Void voidStaticFunction(Void v) {
            return null;
        }
        public static void main(String[] args) {
            final Car carX = new Car(155);
            final Car carY = new Car(140);
    
            final List<Car> cars = new ArrayList<>();
            cars.add(carX);
            cars.add(carY);
    
            cars.sort(Comparator.comparing(Car::getMaxSpeed));
            final Function<Car, Integer> function1 = c->c.getMaxSpeed();
            final Function<Car, Integer> function2 = Car::getMaxSpeed;
            final Function<Car, Void> function3 = Car::setMaxSpeed;
            final Function<Void, Void> function4 = n->n;
            final Function<Void, Integer> function5 = n->5;
            final Function<Void, Integer> function6 = Car::intStaticFunction;
            final Function<Void, Void> function7 = Car::voidStaticFunction;
            final Function<Car, Integer> function8 = function1::apply;
            final Function<Car, Integer> function9 = function2::apply;
            System.out.println(function1.apply(carX));
            System.out.println(function2.apply(carX));
            System.out.println(function8.apply(carX));
            System.out.println(function9.apply(carX));
            System.out.println(function3.apply(carX));
            System.out.println(function1.apply(carX));
            System.out.println(function2.apply(carX));
            System.out.println(function8.apply(carX));
            System.out.println(function9.apply(carX));
            System.out.println();
            System.out.println(function4.apply(null));
            System.out.println(function5.apply(null));
            System.out.println(function6.apply(null));
            System.out.println(function7.apply(null));
        }
    }
    
    0 讨论(0)
  • 2021-02-13 16:29

    That is because the getMaxSpeed method is a Function<Car, Integer>.

    Namely:

    <Car, Integer> Comparator<Car> java.util.Comparator.comparing(
        Function<? super Car, ? extends Integer> keyExtractor
    )
    

    Note

    In order to reference getMaxSpeed from an instance of Car with the :: idiom, you would have to declare a Car method with signature: getMaxSpeed(Car car).

    0 讨论(0)
  • 2021-02-13 16:33

    The assignment:

    Function<Void, Integer> function = carX::getMaxSpeed;
    

    does not compile because it's a Supplier<Integer>, not a Function.

    So then, why does this compile?:

    Comparator.comparing(Car::getMaxSpeed)
    

    Java 8 allows an instance method reference that is a Supplier<U> to be provided where a Function<T, U> is expected, and the compiler effectively converts the getter method into a function.

    To find out why this is possible, let's look at how we invoke a getter method using reflection:

    System.out.println(Car.class.getMethod("getMaxSpeed").invoke(carX)); // "155"
    

    When calling invoke() on an instance method, we pass the instance to the invoke() method of the getter's Method - there's an implied parameter of the instance type. When looked at it this way, we see that under the hood a getter is really implemented as a Function<T, U> via the invoke() method.

    0 讨论(0)
  • 2021-02-13 16:36

    If you want to create a method reference for a method that takes no parameters, such as a method already bound to an instance, you should use a Supplier, not a Function:

    Function<Car, Integer> f1 = Car::getMaxSpeed;
    
    Car carx = new Car(42);
    Supplier<Integer> f2 = carx::getMaxSpeed; 
    

    In the method reference carX::getMaxSpeed, the "implicit" this-parameter of the function is already bound to carx, so you are left with a no-parameter-function (which, by the way, can not be used in a Comparator), and in Java 8, a no-parameter-function is just a Supplier.

    Similarly, if you have a method that returns void, you end up with a Comsumer:

    Consumer<Integer> f3 = carx::setMaxSpeed;
    
    0 讨论(0)
提交回复
热议问题