La forma más limpia de crear un guava MultiMap a partir de un flujo java8 [duplicar]


Esta pregunta ya tiene una respuesta aquí:

Tengo un List<Foo> y quiero un Multimap<String, Foo> donde hemos agrupado los Foo's por su función getId().

Estoy usando Java 8 y su casi impresionante en que se puede hacer:

List<Foo> foos = ...
Map<String, List<Foo>> foosById = foos.stream().collect(groupingBy(Foo::getId));

Sin embargo, yo tener una buena cantidad de código que quiere un MultiMap<String, Foo> así que esto no me ahorra nada y estoy de vuelta a usar un for-loop para crear mi MultiMap. ¿Hay una manera "funcional" agradable que me estoy perdiendo?

Author: Scott B, 2014-04-11

1 answers

Solo puede usar la fábrica de Multimaps de Guayaba:

Multimaps.index(foos, Foo::getId);

O empaquetar una llamada a Multimaps.índice con una interfaz de recopilador (se muestra a continuación, en una implementación ingenua no optimizada).

Multimap<String, Foo> collect = foos.stream().collect(MultimapCollector.toMultimap(Foo::getId));

Y el Coleccionista:

public class MultimapCollector<T, K, V> implements Collector<T, Multimap<K, V>, Multimap<K, V>> {

    private final Function<T, K> keyGetter;
    private final Function<T, V> valueGetter;

    public MultimapCollector(Function<T, K> keyGetter, Function<T, V> valueGetter) {
        this.keyGetter = keyGetter;
        this.valueGetter = valueGetter;
    }

    public static <T, K, V> MultimapCollector<T, K, V> toMultimap(Function<T, K> keyGetter, Function<T, V> valueGetter) {
        return new MultimapCollector<>(keyGetter, valueGetter);
    }

    public static <T, K, V> MultimapCollector<T, K, T> toMultimap(Function<T, K> keyGetter) {
        return new MultimapCollector<>(keyGetter, v -> v);
    }

    @Override
    public Supplier<Multimap<K, V>> supplier() {
        return ArrayListMultimap::create;
    }

    @Override
    public BiConsumer<Multimap<K, V>, T> accumulator() {
        return (map, element) -> map.put(keyGetter.apply(element), valueGetter.apply(element));
    }

    @Override
    public BinaryOperator<Multimap<K, V>> combiner() {
        return (map1, map2) -> {
            map1.putAll(map2);
            return map1;
        };
    }

    @Override
    public Function<Multimap<K, V>, Multimap<K, V>> finisher() {
        return map -> map;
    }

    @Override
    public Set<Characteristics> characteristics() {
        return ImmutableSet.of(Characteristics.IDENTITY_FINISH);
    }
}
 71
Author: Burg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-11 05:19:29