Java 8 Collectors.toMap SortedMapa
sort map java 8 (4)
Basado en la confirmación de dkatzel de que no hay un buen método de API, he optado por mantener mi propia clase de coleccionistas personalizados:
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);
}
}
Estoy usando Java 8 lambdas y quiero usar Collectors
toMap
para devolver SortedMap
. Lo mejor que se me ocurre es llamar al siguiente método Collectors
toMap
con un dummy mergeFunction
y mapSupplier
igual a TreeMap::new
.
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,
BinaryOperator<U> mergeFunction,
Supplier<M> mapSupplier) {
BiConsumer<M, T> accumulator = (map, element) -> map.merge(keyMapper.apply(element),
valueMapper.apply(element), mergeFunction);
return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
}
No quiero pasar una función de fusión, ya que solo quiero throwingMerger()
, de la misma manera que la implementación básica de toMap
siguiente manera:
public static <T, K, U>
Collector<T, ?, Map<K, U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper) {
return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}
¿Cuál sería el método de mejores prácticas para utilizar los Collectors
para devolver un SortedMap
?
No creo que puedas ser mucho mejor que esto:
.collect(Collectors.toMap(keyMapper, valueMapper,
(v1,v2) ->{ throw new RuntimeException(String.format("Duplicate key for values %s and %s", v1, v2));},
TreeMap::new));
donde throw
lambda es lo mismo que throwingMerger()
pero no puedo llamarlo directamente porque es un paquete privado (por supuesto, siempre puedes crear tu propio método estático para eso como throwingMerger()
).
Otra forma de hacerlo es permitir que Collectors.toMap () devuelva cualquier mapa que vaya a devolver, y luego pasarlo a un nuevo TreeMap <> ().
La advertencia es que esto solo funciona si tus "hashCode () + equals ()" y "compareTo" son consistentes. Si no son consistentes, terminará con el HashMap eliminando un conjunto diferente de claves que su TreeMap.
Parece que no hay una forma estándar de hacerlo sin definir tu propio método throwingMerger()
o usar lambda explícito. En mi biblioteca StreamEx toSortedMap
método toSortedMap
que también uses mi propio throwingMerger()
.