Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

thenComparing function throws 'no instance(s) of type variable(s) U exist so that Object conforms to Comparable<? super U>'

What is a proper usage of the thenComparing function and why this option is not working properly? I dont quite understand the errors that are thrown…

Error: no instance(s) of type variable(s) U exist so that Object conforms to Comparable<? super U>

    cards.stream()
            .collect(Collectors.groupingBy(card -> card.kind.rank, Collectors.counting()))
            .entrySet().stream()
            .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()).thenComparing(Map.Entry::getKey))
            .forEachOrdered(e -> sortedCards.put(e.getKey(), e.getValue()));

My card class:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

    public class Card implements Comparable<Card> {
    
        public final Kind kind;
// constructors
    }

Kind class:

    public enum Kind {
        TWO(1, "2"),
        THREE(2, "3"),
        FOUR(3, "4"),
// etc.
// constructos
}

>Solution :

The reason of the compilation error you’ve encountered is a type inference issue.

The when you’re chaining methods while constructing a comparator, the compiler fails to infer the type of the method reference from the target type.

You can resolve it by using type-witness, i.e. providing the types of key and value explosively in the angle brackets <K,V> (these are the types declared by comparingByValue() which produces the first comparator in the chain):

Map.Entry.<Integer, Long>comparingByValue(Comparator.reverseOrder())
    .thenComparing(Map.Entry::getKey)

Also, instead of forEachOrdered() it would be better to use collect() and generate a Map as a result of the stream execution then populate pre-created map via side-effects. It makes your code more verbose and less expressive because you need to instantiate the resulting collection separately, and goes against the guidelines listed in the documentation.

Methods forEach() and forEachOrdered() exist as a last resort, and it’s discouraged to use them as a substitution of reduction operations like collect() or reduce(), for more information refer to the API documentation, pay attention to the code examples.

That’s how it would look like if we make use of collect():

Map<Integer, Long> sortedCards = cards.stream()
    .collect(Collectors.groupingBy(card -> card.kind.rank, Collectors.counting()))
    .entrySet().stream()
    .sorted(Map.Entry.<Integer, Long>comparingByValue(Comparator.reverseOrder())
        .thenComparing(Map.Entry::getKey))
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        Map.Entry::getValue
    ));
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading