Рекурсивные обобщения
Есть ли способ сделать этот метод должным образом универсальным и избавиться от предупреждений?
/**
* <p>Sort a collection by a certain "value" in its entries. This value is retrieved using
* the given <code>valueFunction</code> which takes an entry as argument and returns
* its value.</p>
*
* <p>Example:</p>
* <pre>// sort tiles by number
*Collects.sortByValue(tileList, true, new Function<Integer,NormalTile>() {
* public Integer call(NormalTile t) {
* return t.getNumber();
* }
*});</pre>
*
* @param list The collection.
* @param ascending Whether to sort ascending (<code>true</code>) or descending (<code>false</code>).
* @param valueFunction The function that retrieves the value of an entry.
*/
public static <T> void sortByValue(List<T> list, final boolean ascending, @SuppressWarnings("rawtypes") final Function<? extends Comparable, T> valueFunction) {
Collections.sort(list, new Comparator<T>() {
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override public int compare(T o1, T o2) {
final Comparable v1 = valueFunction.call(o1);
final Comparable v2 = valueFunction.call(o2);
return v1.compareTo(v2) * (ascending ? 1 : -1);
}
});
}
Я пробовал Function<? extends Comparable<?>, T> и Function<? extends Comparable<? extends Comparable>, T>, но ни один не компилировался, с ошибкой при вызове compareTo. Для первого это означает:
Метод compareTo (захват#9-оф ?) в типе Comparable не применяется для Аргументов (capture#10-of ? расширяет сопоставимое)
3 ответов:
Попробуйте это:
public static <T, C extends Comparable<? super C>> void sortByValue(List<T> list, final boolean ascending, final Function<C, T> valueFunction) { Collections.sort(list, new Comparator<T>() { @Override public int compare(T o1, T o2) { final C v1 = valueFunction.apply(o1); final C v2 = valueFunction.apply(o2); return v1.compareTo(v2) * (ascending ? 1 : -1); } }); }Вам также понадобится
super, чтобы разрешить компараторы, определенные для подтипов. Дополнительные пояснения здесь: http://docs.oracle.com/javase/tutorial/extra/generics/morefun.htmlОбновить
Кроме того, глядя на ваш код я вижу еще один велосипед, есть хорошая библиотека Google Collections, которая обеспечивает очень удобное упорядочивание понятие для его обработки.
Итак, ваш код будет выглядеть следующим образом:
Ordering<NormalTile> myOrdering = Ordering.natural() .onResultOf(new Function<Integer,NormalTile>() { public Integer call(NormalTile t) { return t.getNumber(); })) .nullsLast(); ... Collections.sort(list, myOrdering); //or newList = myOrdering.sortedCopy(readonlyList);
Это работает для меня (компилятор Eclipse)
public static <T, U extends Comparable<U>> void sortByValue( List<T> list, final boolean ascending, final Function<U, T> valueFunction) { Collections.sort(list, new Comparator<T>() { @Override public int compare(T o1, T o2) { final U v1 = valueFunction.call(o1); final U v2 = valueFunction.call(o2); return v1.compareTo(v2) * (ascending ? 1 : -1); } }); }Как и другие опубликованные, вы можете даже пойти дальше и объявить
UкакU extends Comparable<? super U>Это пригодится, если у вас есть больше аргументов метода / возвращаемых значений в зависимости от
U
Что делать, если вы объявите два параметра для функции?
public static <T,C extends Comparable<C>> void sortByValue(List<T> list, final boolean ascending, final Function<C, T> valueFunction) { ... final C v1 = ... final C v2 ...Я еще не проверил себя с помощью компилятора (у меня нет ваших интерфейсов, и я слишком голоден, чтобы издеваться над ними:)), но дайте ему шанс.
Я также слишком слаб, чтобы рассуждать о том, должно ли это бытьC extends Comparable<C>илиC extends Comparable<? super C>. Я думаю, что первое будет работать и будет немного более общим, хотя на практике большинство классов не реализуют сопоставимых, кроме как против самих себя.
Comments