Рекурсивные обобщения



Есть ли способ сделать этот метод должным образом универсальным и избавиться от предупреждений?



/**
* <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 ? расширяет сопоставимое)


521   3  

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

    Ничего не найдено.