Reputation: 697
Trying to understand Method references and am having a hard time around it. Stuck with the comparator example.
To make things easier for my brain I keep starting from the basics ( anonymous class implementation >> lamba expression >> method reference ) It is with method references and Comparator example that I am not able to get it to work.
POJO that I want to sort ( picked up from some internet example - mkyong)
public class Fruit{
private int quantity;
private String name;
....
}
Creating test data to play with:
Fruit[] fruits = new Fruit[3];
Fruit pineapple = new Fruit("pineapple",10);
Fruit orange= new Fruit("orange",4);
Fruit kiwi= new Fruit("kiwi",15);
fruits[0] = pineapple;
fruits[1] = orange;
fruits[2] = kiwi;
The Anonymous sorting class implementation:
Comparator<Fruit> anonymousSortByname = new Comparator<Fruit>(){
public int compare(Fruit f1,Fruit f2){
return f1.getName().compareTo(f2.getName());
}
};
To sort :
Arrays.sort(fruits,anonymousSortByname);
Now that this works I have understood that anonymous classes can be converted into lambda expressions ( provided they are functional interfaces etc ... )
The Lambda implementation:
Comparator<Fruit> lambdaSortByname =
(Fruit f1,Fruit f2) -> f1.getName().compareTo(f2.getName());
Ok so things are making sense upto this point.
My understanding: "wherever lambdas are used they could be replaced with 'Method references'"
Did read on SO and over the internet that it is not mandatory to use 'Method references' but my goal is to understand them - so whether to use or not is not my question :)
Also was reading here: method reference1 and here and here . However I am having a difficult time with Method reference specifically when I am trying to implement it with Comparator.
Here is what I have tried and it gives me a compilation error.
Comparator<Fruit> methodRefComparator = Comparator::compare;
Error on compilation:
Cannot make a static reference to non static block of code
In the links the example does talk about a method 'comparing' in Comparator interface but gets fuzzy at this point....
Edit#1
Based on comments below have revised the question:
The confusion is around how 'comparing' method of Comparator works.
I did get a working example ( by googling and not by my own understanding) :
First created a function that accepts a 'Fruit' as input and returns a String.
Function<Fruit, String> funcName = (Fruit f1) -> f1.getName();
Then passed this 'Function' to the 'comparing' method of 'Comparator' to get back the desired comparator.
Comparator<Fruit> sortByName = Comparator.comparing(funcName);
Now the sorting works:
Arrays.sort(fruits,sortByName );
but .. am unable to get my head around how does it work . I have not provided the implementation of the Comparator ( f1.getName() - f2.getName()) so how did it work ?
Is this more like a contract where the compiler is able to understand that since I have provided it a function with the implementation of 'getName' it would use it in the returned Comparator ?
Upvotes: 3
Views: 6835
Reputation: 298539
Comparator.comparing
is a static
factory method creating a comparator which will delegate to the function you provided, for getting the property values to compare. It’s basically like this:
public static <T, U extends Comparable<? super U>>
Comparator<T> comparing(Function<? super T, ? extends U> func) {
return (o1, o2) -> func.apply(o1).compareTo(func.apply(o2));
}
So the logic of evaluating the function for both arguments and invoking compareTo
with the results, is right there.
Since this is common to all comparators comparing a property of the elements, it was a natural decision to put the common code into a shared method. This separation also simplified the function you have to provide, as it only needs to express, how to get the property value.
Since this more than often implies just invoking a single (getter) method, it allows expression the function as method reference, which is only possible when there is a single existing method doing what your function is supposed to do, i.e.
Arrays.sort(fruits, Comparator.comparing(Fruit::getName));
where Fruit::getName
is equivalent to (Fruit f) -> f.getName()
.
So, not every lambda expression can be replaced with a method reference. You can replace a lambda expression when it consists of a single method invocation or when a utility method helps you reducing the logic on your side to a function consisting of a single method invocation.
Upvotes: 7
Reputation: 92
When you use ->, you can use variable in function. When you use ::, the function using default variable.
Your source code compile fail because function compare was implement with 2 variable and you was put 0 variable.
Upvotes: 0