I am working on the following little utility class:
public class Collections2 {
public static <T, K extends Comparable<? super K>> Comparator<T>
comparatorBy(Function<T, K> selector) {
return (a, b) -> selector.apply(a).compareTo(selector.apply(b));
}
public static <T, K extends Comparable<? super K>> void
sortBy(List<T> list, Function<? super T, K> selector) {
Collections.sort(list, comparatorBy(selector));
}
}
This allows sorting by python style key functions, so I don't have to write full comparators for every field I want to sort by, instead I can just write:
List<Person> persons = ...;
Collections2.sortBy(persons, Person::getName);
This is nice, I imagine writing lots of utility methods with this style like minBy
, maxBy
, groupBy
, and so on.
But what if somebody want to use these new utility functions with a comparison they already have? I thought of the following:
public static class KeyByComparator<T> implements Comparable<KeyByComparator<T>> {
private T target;
private Comparator<? super T> comparator;
public KeyByComparator(T target, Comparator<? super T> comparator) {
this.target = target;
this.comparator = comparator;
}
@Override
public int compareTo(KeyByComparator<T> other) {
return this.comparator.compare(this.target, other.target);
}
}
public static <T> Function<T, KeyByComparator<T>> keysByComparator(Comparator<? super T> comparator) {
return t -> new KeyByComparator<T>(t, comparator);
}
So they could use it this way:
public static final Comparator<Person> LEGACY_COMPARATOR = ...;
// ...
Collections2.sortBy(persons, Collections2.keysByComparator(LEGACY_COMPARATOR));
// Ignore the fact that regular sort would be shorter
// Collections.sort(persons, LEGACY_COMPARATOR)
But to achieve this, I had to make KeyByComparator<T>
public.
What if I dont want to expose the KeyByComparator<T>
class? Here is what I tried:
public static <T, K extends Comparable<? super K>> Function<T, K>
keysByComparator2(Comparator<? super T> comparator) {
return t -> new KeyByComparator<T>(t, comparator);
}
But it gives this compilation error:
Type mismatch: cannot convert from Collections2.KeyByComparator<T> to K
Is there some fancy generic type constraint for return values?