Java 8 collector for Guava immutable collections?

前端 未结 5 2244
花落未央
花落未央 2020-12-17 09:55

I really like Java 8 streams and Guava\'s immutable collections, but I can\'t figure out how to use the two together.

For example, how do I implement a Java 8 Collec

5条回答
  •  渐次进展
    2020-12-17 10:22

    Update: I found an implementation that seems to cover all Guava collections at https://github.com/yanaga/guava-stream and attempted to improve upon it in my own library at https://bitbucket.org/cowwoc/guava-jdk8/

    I'm leaving the previous answer below, for historical reasons.


    Holy #@!( I got it!

    This implementation works for any Multimap (mutable or immutable) whereas shmosel's solution focuses on immutable implementations. That said, the latter might be more efficient for the immutable case (I don't use a builder).

    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.
     * 

    * @author Gili Tzabari * @param the type of the input elements * @param the type of keys stored in the map * @param the type of values stored in the map * @param the output type of the collector */ public final class MultimapCollector> implements Collector, R> { private final Supplier> mapSupplier; private final Function keyMapper; private final Function valueMapper; private final Function, R> resultMapper; /** * Creates a new MultimapCollector. *

    * @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> mapSupplier, Function keyMapper, Function valueMapper, Function, 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> supplier() { return mapSupplier; } @Override public BiConsumer, 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> combiner() { return (left, right) -> { left.putAll(right); return left; }; } @Override public Function, R> finisher() { return resultMapper; } @Override public Set 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.
     * 

    * @author Gili Tzabari */ public final class GuavaCollectors { /** * Returns a {@code Collector} that accumulates elements into a {@code Multimap}. *

    * @param the type of the input elements * @param the type of the map keys * @param the type of the map values * @param 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 > Collector toMultimap( Supplier> mapSupplier, Function keyMapper, Function valueMapper, Function, R> resultMapper) { return new MultimapCollector<>(mapSupplier, keyMapper, valueMapper, resultMapper); } public static void main(String[] args) { Multimap input = HashMultimap.create(); input.put(10, 20.0); input.put(10, 25.0); input.put(50, 60.0); System.out.println("input: " + input); ImmutableMultimap 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() outputs:

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

    Resources

    • Arjit provided an excellent resource demonstrating how to implement Collectors for other Guava collections: http://blog.comsysto.com/2014/11/12/java-8-collectors-for-guava-collections/

提交回复
热议问题