Unexpected behavior when using Comparator.comparing(HashMap::get) as a comparator
bookshelf.keySet().stream().sorted(Comparator.comparing(bookshelf::get))
From the above snippet in your example, we can see that you're trying to sort the keys of bookshelf
by their respective value.
The issue with this is that two book names could be mapped to the same age recommendation. Because you only have a single Comparator
and because HashMap
does not specify a consistent ordering, you have a chance at ending up with different results for the same inputs.
To ameliorate this, you can use thenComparing
to handle the case when duplicate value-mappings are encountered:
bookshelf.entrySet()
.stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().thenComparing(Map.Entry.comparingByKey()))
.forEach(entry -> System.out.println(entry.getKey() + " (recommended for " + entry.getValue() + " year-olds or older)"));
Build the Comparator of Entry and use Entry::getValue
and Entry::getKey
to sort by value then by key
Comparator<Entry<String, Integer>> cmp = Comparator.comparing(Entry::getValue);
bookshelf.entrySet()
.stream()
.sorted(cmp.thenComparing(Entry::getKey))
.forEach(entry -> System.out.println(entry.getKey() + " (recommended for " + entry.getValue() + " year-olds or older)"));
This is happening since you are only using "key" to compare. You should compare them by both "key" and "value". This should work fine:
bookshelf.entrySet()
.stream()
.sorted(Map.Entry.<String,Integer>comparingByValue()
.thenComparing(Map.Entry.comparingByKey()))
.map(e -> e.getKey())
.forEach((key) -> System.out.println(key + " (recommended for " + bookshelf.get(key) + " year-olds or older)"));