2011-12-07 3 views
4

Existe-t-il un moyen de rendre cette méthode générique et de supprimer les avertissements?Génériques récursifs

/** 
* <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); 
     } 
    }); 
} 

J'ai essayé Function<? extends Comparable<?>, T> et Function<? extends Comparable<? extends Comparable>, T> mais ni compilé, avec une erreur sur l'appel à compareTo. Pour la première qui est: (capture # 10 de s'étend Comparable)

La méthode compareTo (? Capture # 9 de) dans le type Comparable n'est pas applicable pour les arguments

+0

Pouvez-vous fournir également la classe 'Function'? – melihcelik

+1

Salut, je jette un coup d'oeil à la question et je n'arrive vraiment à rien. Mais un de mes commentaires est, ne niez pas le résultat de 'compareTo()', car si quelqu'un retourne 'Integer.MIN_VALUE' il restera' Integer.MIN_VALUE' et l'ordre de tri ne sera pas ce que vous vouliez. Au lieu de cela, lorsque l'ascendant est faux, inversez l'appel, par ex. de 'a.compareTo (b)' à 'b.compareTo (a);'. J'ennuie je sais ... – Grundlefleck

+0

@Grundlefleck Merci, j'ai implémenté ça. –

Répondre

5

Essayez ceci:

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); 
     } 
    }); 
} 

Vous avez également besoin du super pour autoriser les comparateurs définis pour les sous-types. Plus d'explications ici: http://docs.oracle.com/javase/tutorial/extra/generics/morefun.html

MISE À JOUR

Aussi, en regardant votre code, je vois encore un autre vélo, il y a une bonne bibliothèque Les collections Google, qui fournit des Ordering très pratique notion de le manipuler.

Ainsi, votre code ressemblerait à ceci:

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); 
+0

Hmm, vous avez toujours le type brut 'Comparable' ... Et vous vouliez probablement dire'? super C', pas 'T'. Dans ce cas, 'super' est une bonne idée, mais pas nécessaire car il n'y a pas d'autre argument dépendant de' C' –

+0

Oh, je l'ai modifié. – kan

+0

+1 pour cet exemple de collections Google –

1

Qu'est-ce que si vous déclarez deux paramètres pour la fonction?

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 ... 

N'a pas bon sens moi-même vérifié avec un compilateur (ne pas vos interfaces et je suis trop faim pour se moquer d'eux :)), mais donner un coup de feu.

Je suis également trop étourdi pour savoir si ce devrait être C extends Comparable<C> ou C extends Comparable<? super C>. Je pense que le premier fonctionnerait et serait un peu plus général, bien que dans la pratique, la plupart des classes n'appliquent pas Comparable sauf contre eux-mêmes.

+0

peut-être aussi utiliser '>' pour une solution plus générique –

+0

@ratchetfreak ha, vient d'éditer ma propre réponse pour l'ajouter. :) Question importante: "pour une solution plus générique", jeu de mots? – yshavit

2

Cela fonctionne pour moi (compilateur 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); 
    } 
    }); 
} 

Comme d'autres affichés, vous pouvez même aller plus loin et déclarer U comme

U extends Comparable<? super U> 

Ce sera utile si vous avez plus d'arguments de méthode/renvoyer des valeurs en fonction de U

+0

Pour moi, ce code compilera, mais les appels à cette méthode ne le feront pas. À quoi ressemblerait une invocation? – Grundlefleck

+1

Découvrez le Javadoc de l'OP ... –