开发者

Generic method to Sort a Map on Values

I have a small program that is supposed to sort a map based on its values. Here is what I have so far:

    public static <K, V extends Comparable< ? extends V>> Map<K, V> 
    sortByValues(final Map <K, V> mapToSort)
    {
        List<Map.Entry<K, V>> entries = 
            new ArrayList<Map.Entry<K, V>>(mapToSort.size());

        entries.addAll(mapToSort.entrySet());

        Collections.sort(entries, new Comparator<Map.Entry<K, V>>()
        {
            public int compare(
                               final Map.Entry<K, V> entry1, 
                               final Map.Entry<K, V> entry2)
            {
                return entry1.getValue(开发者_开发知识库).compareTo(entry2.getValue());
            }
        });

        Map<K, V> sortedMap = new LinkedHashMap<K, V>();

        for (Map.Entry<K, V> entry : entries)
        {
            sortedMap.put(entry.getKey(), entry.getValue());
        }

        return sortedMap; 
    }

I want my generic value V to be comparable to anything that is either V or is a at least a subclass of V.

I get the following error for the code piece :

public static <K, V extends Comparable< ? extends V>>

Bound mismatch: The method compareTo(? extends V) of type V is not applicable for the arguments (V). The wildcard parameter ? extends V has no lower bound, and may actually be more restrictive than argument V

How can it be more restrictive?

If I change the declaration to:

public static <K, V extends Comparable< ? super V>>

then there is no error. But this is not what I want.

One workaround I have is that, I can change the declaration to:

public static <K, V extends Comparable<V>>

but doing this I lose the flexibility in that I cannot pass a Map whose value implements Comparable with a subclass of itself.

Apologies for such a long question. Thanks in advance.


I think your second option, namely

public static <K, V extends Comparable<? super V>>

is the way to. I think this is so because when you write

public static <K, V extends Comparable<C extends V>>

you basically say that you want to be able to compare any instance of V to any instance of C. But what is missing here is, that because you want to call Collections.sort(..) internally, you also must be able to compare any instance of C to any instance of V. But the generics do not express this, and rightfully the compiler complains.

Basically, to sort some values (at least using Collections.sort(..)) they must be mutually comparable, but the generic restrictions you envision only guarantee that you can compare in one direction.


implements Comparable with a subclass of itself.

This is "poor design": As a good general rule, classes should not know about their subclasses.

What use case do you have in mind?

I think public static <K, V extends Comparable<V>> is fine.


I think you wanted V to be an extension of some type T. Try adding a temporary type T, as follows in the template declaration:

public static <K, T extends Comparable<T>, V extends T> Map<K, V> 
    sortByValues(final Map <K, V> mapToSort)

everything else remains the same. If you didn't mean that, that is all your Comparables are going to be a sub type of V, then public static <K, V extends Comparable<V>> makes sense, because from V's point of view, the child class of V that overrides compareTo is going to call the compareTo method with the same signature as the compareTo method that V has. Ie, The compareTo method that V declares is what is going to be called (but it may be the overridden definition in V's child class). And so, V extends Comparable<V> is sufficient and correct. I hope I've made myself clear.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜