Comparator.reversed() does not compile using lambda
This is a weakness in the compiler's type inferencing mechanism. In order to infer the type of u
in the lambda, the target type for the lambda needs to be established. This is accomplished as follows. userList.sort()
is expecting an argument of type Comparator<User>
. In the first line, Comparator.comparing()
needs to return Comparator<User>
. This implies that Comparator.comparing()
needs a Function
that takes a User
argument. Thus in the lambda on the first line, u
must be of type User
and everything works.
In the second and third lines, the target typing is disrupted by the presence of the call to reversed()
. I'm not entirely sure why; both the receiver and the return type of reversed()
are Comparator<T>
so it seems like the target type should be propagated back to the receiver, but it isn't. (Like I said, it's a weakness.)
In the second line, the method reference provides additional type information that fills this gap. This information is absent from the third line, so the compiler infers u
to be Object
(the inference fallback of last resort), which fails.
Obviously if you can use a method reference, do that and it'll work. Sometimes you can't use a method reference, e.g., if you want to pass an additional parameter, so you have to use a lambda expression. In that case you'd provide an explicit parameter type in the lambda:
userList.sort(Comparator.comparing((User u) -> u.getName()).reversed());
It might be possible for the compiler to be enhanced to cover this case in a future release.
Comparator reversed() is resulting in compiler error
you can find similar issue here: Comparator.reversed() does not compile using lambda
solution was to do something like this:
Collections.sort(ducks, Comparator.comparing((Duck d) -> d.getHeadSize()).reversed());
Edit:
adding related bugs with this issue:
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8025138
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8025290
Can not reversed sort of ArrayList in java
AFAIK, there's some bug in compiler that they somehow can't guess the correct type when chaining Comparator
.
In your case you can workaround by using method reference:
List<Movie> result = movieRepository.findAll();
result.sort(Comparator.comparing(Movie::getRating).reversed());
Method Reference works for Comparator.comparing method whereas a lambda expression isn't working
The problem is with this expression:
Comparator.comparing(person -> person.getAge()).thenComparing(person -> person.getName())
In the first part Comparator.comparing(person -> person.getAge())
, the compiler is not able to infer the type of the lambda argument as Person
, because the expression is not assigned to a variable that helps infer that information.
On the other hand, when removing the thenComparing()
part, the compiler can infer the type of the lambda argument, because the comparator Comparator.comparing(person -> person.getAge())
is targeted as argument to the sorted()
method, which is being invoked on a Stream<Person>
.
Note that if you explicitly specify the type of the argument, it works:
Comparator.comparing((Person person) -> person.getAge()).thenComparing(person -> person.getName())
How to use a Java8 lambda to sort a stream in reverse order?
You can adapt the solution you linked in How to sort ArrayList<Long> in Java in decreasing order? by wrapping it in a lambda:
.sorted((f1, f2) -> Long.compare(f2.lastModified(), f1.lastModified())
note that f2 is the first argument of Long.compare
, not the second, so the result will be reversed.
Easier way to reverse a comparator created by a static method (Functional Interface) inline?
You can write a method that accepts a Comparator
as argument and reverses it:
public static <T> Comparator<T> reverse(Comparator<T> comparator) {
return comparator.reversed();
}
You would probably do this in a class full of utility methods and statically import the method.
Then you can do:
reverse(Instant:compareTo)
Sorting array with streams using reversed comparator
The compiler is not able to infer the generic type parameters to comparing()
when you add the .reversed()
chain call, so you have to explicitly give them.
First, you need to be aware of the full declaration of comparing()
:
static <T,U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T,? extends U> keyExtractor)
It has two type parameters:
T
- The input to the function (lambda), i.e.String[]
in your caseU
- The return value of the function, i.e.String
in your case
So you can write:
Comparator.<String[], String>comparing(x -> x[1]).reversed()
Alternatively, you can just specify the parameter type in your lambda (i.e. T
), and the compiler will infer U
.
Comparator.comparing((String[] x) -> x[1]).reversed()
That's probably the way you'd want to do it.
You can also do either of those to the first one, if you like. These are all the same, just becoming more and more explicit:
Comparator.comparing(x -> x[1])
Comparator.comparing((String[] x) -> x[1])
Comparator.<String[], String>comparing(x -> x[1])
Comparator.<String[], String>comparing((String[] x) -> x[1])
Related Topics
How to Get the Current Date/Time in Java
What Is @Modelattribute in Spring MVC
Generate/Get Xpath from Xml Node Java
Most Simple Code to Populate Jtable from Resultset
Differencebetween Serializable and Externalizable in Java
Auto Errors Detection in Intellij Idea
Avoid Jackson Serialization on Non Fetched Lazy Objects
Places Where Javabeans Are Used
String's Maximum Length in Java - Calling Length() Method
How to Search Google Programmatically Java API
How to Kill a Thread? Without Using Stop();
Differences in Boolean Operators: & VS && and | VS ||
Handling Parenthesis While Converting Infix Expressions to Postfix Expressions
Is There a Concurrent List in Java's Jdk
Why Does Integer Division Code Give the Wrong Answer
Java.Rmi.Serverexception: Remoteexception Occurred in Server Thread (Classnotfoundexception)