Java - 是否有任何Stream收集器返回ImmutableMap?

时间:2015-12-29 06:49:49

标签: java-8 guava

我发现自己想要一个Collectors.toMap的变体,它会返回ImmutableMap,这样我才能做到:

ImmutableMap result = list.stream().collect(MyCollectors.toImmutableMap(
    tuple -> tuple._1(), tuple -> tuple._2());

(此特定示例中的tuple是Scala Tuple2

我已经just learned这种方法将在Guava 21中提供Java-8支持(耶!)但这听起来好一个月之后。有谁知道今天可能实现这个的任何现有库(等)?

ImmutableMap并非严格要求,但似乎是我要求的最佳选择:按键查找,并保留原始迭代顺序。不变性也是首选。

注意FluentIterable.toMap(Function)是不够的,因为我需要键映射函数和值映射函数。

2 个答案:

答案 0 :(得分:19)

您不需要为此收集器编写匿名类。您可以改为使用Collector.of

public static <T, K, V> Collector<T, ?, ImmutableMap<K,V>> toImmutableMap(
            Function<? super T, ? extends K> keyMapper,
            Function<? super T, ? extends V> valueMapper) {
    return Collector.of(
               ImmutableMap.Builder<K, V>::new,
               (b, e) -> b.put(keyMapper.apply(e), valueMapper.apply(e)),
               (b1, b2) -> b1.putAll(b2.build()),
               ImmutableMap.Builder::build);
}

或者,如果您不介意首先将结果收集到可变映射中,然后将数据复制到不可变映射中,则可以使用内置toMap收集器与collectingAndThen结合使用:

ImmutableMap<String, String> result = 
     list.stream()
         .collect(collectingAndThen(
             toMap(
                 tuple -> tuple._1(), 
                 tuple -> tuple._2()),
             ImmutableMap::copyOf));

答案 1 :(得分:0)

由于我还没有找到这样的收藏家图书馆,所以我会在我需要的具体问题上分享我的第一个错误。这里没有钟声或口哨声! (例如处理或合并重复的密钥。)

请随时提出改进建议。

/**
 * A variant of {@link Collectors#toMap(Function, Function)} for immutable maps.
 * <p>
 * Note this variant throws {@link IllegalArgumentException} upon duplicate keys, rather than
 * {@link IllegalStateException}
 * 
 * @param <T> type of the input elements
 * @param <K> output type of the key mapping function
 * @param <V> output type of the value mapping function
 * @param keyMapper  a mapping function to produce keys
 * @param valueMapper a mapping function to produce values
 * 
 * @return a {@code Collector} which collects elements into a {@code Map} whose keys and values
 *         are the result of applying mapping functions to the input elements
 *         
 * @throws IllegalArgumentException upon duplicate keys
 */
public static <T, K, V> Collector<T, ?, ImmutableMap<K,V>> toImmutableMap(
        Function<? super T, ? extends K> keyMapper,
        Function<? super T, ? extends V> valueMapper) {
    return new Collector<T, ImmutableMap.Builder<K,V>, ImmutableMap<K,V>>() {

        public Supplier<Builder<K, V>> supplier() {
            return ImmutableMap.Builder::new;
        }

        public BiConsumer<Builder<K, V>, T> accumulator() {
            return (builder, element) -> {
                K key = keyMapper.apply(element);
                V value = valueMapper.apply(element);
                builder.put(key, value);
            };
        }

        public BinaryOperator<Builder<K, V>> combiner() {
            return (b1, b2) -> {
                b1.putAll(b2.build());
                return b1;
            };
        }

        public Function<Builder<K, V>, ImmutableMap<K, V>> finisher() {
            return builder -> builder.build();
        }

        public Set<Collector.Characteristics> characteristics() {
            return ImmutableSet.of();
        }
    };
}