I\'m using Java 8 lambdas and want to use Collectors
toMap
to return a SortedMap
. The best I can come up with is to call the following
Based on dkatzel's confirmation that there's not a nice API method, I've opted for maintaining my own custom Collectors class:
public final class StackOverflowExampleCollectors {
private StackOverflowExampleCollectors() {
throw new UnsupportedOperationException();
}
private static <T> BinaryOperator<T> throwingMerger() {
return (u, v) -> {
throw new IllegalStateException(String.format("Duplicate key %s", u));
};
}
public static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper, Supplier<M> mapSupplier) {
return Collectors.toMap(keyMapper, valueMapper, throwingMerger(), mapSupplier);
}
}
I don't think you can get much better than this:
.collect(Collectors.toMap(keyMapper, valueMapper,
(v1,v2) ->{ throw new RuntimeException(String.format("Duplicate key for values %s and %s", v1, v2));},
TreeMap::new));
where the throw
lambda is the same as throwingMerger()
but I can't directly call that since it's package private (you can of course always make your own static method for that like throwingMerger()
is. )
If you use the guava library then you can use:
.collect(ImmutableSortedMap.toImmutableSortedMap(comparator, keyMapper, valueMapper));
The resulting map will be a SortedMap
and also immutable.
Another way you can do this is to allow Collectors.toMap() to return whatever map it is going to return, and then pass that to a new TreeMap<>().
The caveat there is that this only works if your "hashCode()+equals()" and "compareTo" are consistent. If they aren't consistent, then you'll end up with the HashMap removing different set of keys than your TreeMap.
Seems that there's no standard way to do this without defining your own throwingMerger()
method or using explicit lambda. In my StreamEx library I defined the toSortedMap method which also uses my own throwingMerger()
.