Why a method without input parameter can be used to replace Function<T,R>

Viewed 90

For the following code snippet, in calculateOnShipments, one parameter accepts a function with Shipment as input and Double as output.

Function<Shipment, Double> f

1) Why can it be called using Shipment::calculateWeight? calculateWeight() does not accept any parameter, although it returns Double

public double calculateWeight()

2) I try to comment out the calculateWeight() but keep the calculateWeight(Shipment s1), then there is an error message

"Cannot make a static reference to the non-static method calculateWeight(Shipment) from the type Shipment"

What does this message mean? why it said a static reference? before I comment the calculateWeight(), why was there no error message?

class Shipment {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        List<Shipment> l = new ArrayList<Shipment>();
        l.add(new Shipment());
        l.add(new Shipment());
        Shipment shipment1 = new Shipment();
        // Using an anonymous class
        List<Double> lw = shipment1.calculateOnShipments(l, Shipment::calculateWeight);
        System.out.println(lw);//[0.0,0.0]
    }

    public double calculateWeight() {
        double weight = 0;
        // Calculate weight
        return weight;
    }

    public double calculateWeight(Shipment s1) {
        double weight = 1;
        // Calculate weight
        return weight;
    }

    public List<Double> calculateOnShipments(
            List<Shipment> l, Function<Shipment, Double> f) {
        List<Double> results = new ArrayList<>();
        for (Shipment s : l) {
            results.add(f.apply(s));
        }
        return results;
    }
}
2 Answers

why it can be called by Shipment::calculateWeight? calculateWeight() does not accept any parameter, although it return double

It can be called using the method reference since the method reference represent the code to invoke the method calculateWeight on a shipment which is accepted as an input to the Function<Shipment, Double>. Read these for further co-relation --

shipment -> shipment.calculateWeight()

or further

new Function<Shipment, Double>() {
    @Override
    public Double apply(Shipment shipment) {
        return shipment.calculateWeight();
    }
})

I try to comment out the calculateWeight() but keep the calculateWeight(Shipment s1), then there is a error msg

Now if you have understood the above lambda representation, the method reference is not possible without the since invoking calculateWeight method needs a shipment for one to be an instance on which the method would be called and another which would should be passed to the method to be used as a parameter. That could be something like --

shipment -> shipment.calculateWeight(shipment1)

Do note, converting the method to be static such as

public static double calculateWeight(Shipment s1)

would result in inferring the method reference to accept the instance as the parameter itself and would work as:

List<Double> lw = shipment1.calculateOnShipments(l, Shipment::calculateWeight)

where Shipment::calculateWeight represents shipment -> calculateWeight(shipment).

1) By why it can be called by Shipment::calculateWeight? calculateWeight() does not accept any parameter, […]

calculateWeight() is a non-static method on class Shipment, so in a sense, it takes an implicit this parameter of type Shipment. So Shipment::calculateWeight is a function that takes that one parameter. (If calculateWeight() were a non-static method, or if you wrote shipment1::calculateWeight rather than Shipment::calculateWeight so that the instance is baked into the method reference, then that would be a function with no parameters.)


2) I try to comment out the calculateWeight() but keep the calculateWeight(Shipment s1), then there is a error msg

"Cannot make a static reference to the non-static method calculateWeight(Shipment) from the type Shipment"

what does this message mean? why it said a static reference? […]

This is a good question. The underlying problem is that, as far as method references are concerned, calculateWeight(Shipment s1) takes two parameters: the implicit this parameter of type Shipment (since it's an instance method on class Shipment), and the explicit s1 parameter of type Shipment.

The error-message comes out weird; in essence, the compiler is saying "this is not a static method, so you need to give it an instance", the idea being that you could write shipment1::calculateWeight rather than Shipment::calculateWeight to specify the instance it should be called on.

Related