Guava不可变集合的Java 8收集器?

问题描述 投票:21回答:5

我真的很喜欢Java 8流和Guava的不可变集合,但是我不知道如何将两者一起使用。

例如,如何实现将流结果收集到Collector中的Java 8 ImmutableMultimap

奖励积分:我希望能够提供键/值映射器,类似于Collectors.toMap()的工作方式。

java guava java-stream
5个回答
25
投票
.collect(ImmutableSet.toImmutableSet()) .collect(ImmutableMap.toImmutableMap()) .collect(Maps.toImmutableEnumMap()) .collect(Sets.toImmutableEnumSet()) .collect(Tables.toTable()) .collect(ImmutableList.toImmutableList()) .collect(Multimaps.toMultimap(...))

7
投票
Update:我发现一个实现似乎覆盖了https://github.com/yanaga/guava-stream处的所有Guava集合,并尝试在我自己的https://bitbucket.org/cowwoc/guava-jdk8/库中对其进行改进。

出于历史原因,我将下面的答案留在下面。

[圣#@!(我明白了!


此实现适用于任何Multimap(可变或不可变),而shmosel's solution专注于不可变的实现。也就是说,对于不变的情况,后者可能会更有效(我不使用构建器)。

import com.google.common.collect.Multimap; import java.util.EnumSet; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; import java.util.stream.Collector.Characteristics; import org.bitbucket.cowwoc.preconditions.Preconditions; /** * A Stream collector that returns a Multimap. * <p> * @author Gili Tzabari * @param <T> the type of the input elements * @param <K> the type of keys stored in the map * @param <V> the type of values stored in the map * @param <R> the output type of the collector */ public final class MultimapCollector<T, K, V, R extends Multimap<K, V>> implements Collector<T, Multimap<K, V>, R> { private final Supplier<Multimap<K, V>> mapSupplier; private final Function<? super T, ? extends K> keyMapper; private final Function<? super T, ? extends V> valueMapper; private final Function<Multimap<K, V>, R> resultMapper; /** * Creates a new MultimapCollector. * <p> * @param mapSupplier a function which returns a new, empty {@code Multimap} into which intermediate results will be * inserted * @param keyMapper a function that transforms the map keys * @param valueMapper a function that transforms the map values * @param resultMapper a function that transforms the intermediate {@code Multimap} into the final result * @throws NullPointerException if any of the arguments are null */ public MultimapCollector(Supplier<Multimap<K, V>> mapSupplier, Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends V> valueMapper, Function<Multimap<K, V>, R> resultMapper) { Preconditions.requireThat(mapSupplier, "mapSupplier").isNotNull(); Preconditions.requireThat(keyMapper, "keyMapper").isNotNull(); Preconditions.requireThat(valueMapper, "valueMapper").isNotNull(); Preconditions.requireThat(resultMapper, "resultMapper").isNotNull(); this.mapSupplier = mapSupplier; this.keyMapper = keyMapper; this.valueMapper = valueMapper; this.resultMapper = resultMapper; } @Override public Supplier<Multimap<K, V>> supplier() { return mapSupplier; } @Override public BiConsumer<Multimap<K, V>, T> accumulator() { return (map, entry) -> { K key = keyMapper.apply(entry); if (key == null) throw new IllegalArgumentException("keyMapper(" + entry + ") returned null"); V value = valueMapper.apply(entry); if (value == null) throw new IllegalArgumentException("keyMapper(" + entry + ") returned null"); map.put(key, value); }; } @Override public BinaryOperator<Multimap<K, V>> combiner() { return (left, right) -> { left.putAll(right); return left; }; } @Override public Function<Multimap<K, V>, R> finisher() { return resultMapper; } @Override public Set<Characteristics> characteristics() { return EnumSet.noneOf(Characteristics.class); } }

[...]

import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

/**
 * Stream collectors for Guava collections.
 * <p>
 * @author Gili Tzabari
 */
public final class GuavaCollectors
{
    /**
     * Returns a {@code Collector} that accumulates elements into a {@code Multimap}.
     * <p>
     * @param <T>          the type of the input elements
     * @param <K>          the type of the map keys
     * @param <V>          the type of the map values
     * @param <R>          the output type of the collector
     * @param mapSupplier  a function which returns a new, empty {@code Multimap} into which intermediate results will be
     *                     inserted
     * @param keyMapper    a function that transforms the map keys
     * @param valueMapper  a function that transforms the map values
     * @param resultMapper a function that transforms the intermediate {@code Multimap} into the final result
     * @return a {@code Collector} which collects elements into a {@code Multimap} whose keys and values are the result of
     *         applying mapping functions to the input elements
     */
    public static <T, K, V, R extends Multimap<K, V>> Collector<T, ?, R> toMultimap(
        Supplier<Multimap<K, V>> mapSupplier,
        Function<? super T, ? extends K> keyMapper,
        Function<? super T, ? extends V> valueMapper,
        Function<Multimap<K, V>, R> resultMapper)
    {
        return new MultimapCollector<>(mapSupplier, keyMapper, valueMapper, resultMapper);
    }

    public static void main(String[] args)
    {
        Multimap<Integer, Double> input = HashMultimap.create();
        input.put(10, 20.0);
        input.put(10, 25.0);
        input.put(50, 60.0);
        System.out.println("input: " + input);
        ImmutableMultimap<Integer, Double> output = input.entries().stream().collect(
            GuavaCollectors.toMultimap(HashMultimap::create,
                entry -> entry.getKey() + 1, entry -> entry.getValue() - 1,
                ImmutableMultimap::copyOf));
        System.out.println("output: " + output);
    }
}

main()输出:

input: {10=[20.0, 25.0], 50=[60.0]}
output: {51=[59.0], 11=[24.0, 19.0]}

资源

Arjit提供了一个极好的资源,展示了如何为其他Guava集合实现Collector:http://blog.comsysto.com/2014/11/12/java-8-collectors-for-guava-collections/


4
投票

2
投票
Stream<T> stream = ... ImmutableXxx<T> collection = ImmutableXxx.copyOf(stream.iterator());

1
投票
© www.soinside.com 2019 - 2024. All rights reserved.