Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use generic `Number` for `Comparator.comparing`

I have a list of class that I want to sort:

class Student {
    private Integer studentId;
    private Double scoreA;
    private Integer scoreB;
    private Long scoreC;

    // ... getter/setter...
}

And I want to make a helper class (with static methods) that can be used to sort the Student list:

public class SortHelper {
    public static <T> void Sort(List<T> list, Function<T, Double> fn) { // Double
        Collections.sort(list, Comparator.comparing(fn));
    }
}

However, the above method only takes Double - but I'd like to pass all Number object to the method:

public static <T> void Sort(List<T> list, Function<T, Number> fn) { // `Number`
    Collections.sort(list, Comparator.comparing(fn)); // Error!
}

// so that I can do:
List<Student> students = loadStudents();

SortHelper.Sort(students, Student::getScoreA); // Double
SortHelper.Sort(students, Student::getScoreB); // Integer
SortHelper.Sort(students, Student::getScoreC); // Long

When I use Number instead of Double, it gives an error The method comparing(Function<? super T,? extends U>) in the type Comparator is not applicable for the arguments (Function<T,Number>)

My questions are:

  1. Why is using Number instead of Double not possible?
  2. How to improve SortHelper to use Number instead of Double?

Please help me out..!

like image 884
KimchiMan Avatar asked Apr 23 '20 04:04

KimchiMan


1 Answers

I believe you're facing this issue because Comparator#comparing expects a Function<T, U> whose output U extends Comparable<? super U>.

Number does not implement Comparable<? super Number>.

One solution is to specify a new generic type that extends Number and also extends Comparable:

public static <T, U extends Number & Comparable<? super U>> void Sort(List<T> list, Function<T, U> fn) {
    Collections.sort(list, Comparator.comparing(fn));
}

Or equivalently, you can use List#sort:

public static <T, U extends Number & Comparable<? super U>> void Sort(List<T> list, Function<T, U> fn) {
    list.sort(Comparator.comparing(fn));
}

This is what's known as an intersection type.

like image 90
Jacob G. Avatar answered Sep 20 '22 23:09

Jacob G.