Java - 是否有 return ImmutableMap 的流收集器?

Java - Are there any Stream Collectors that return ImmutableMap?

我发现自己想要 Collectors.toMap 的变体,其中 returns 和 ImmutableMap,这样我可以做到:

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

(在此特定示例中,tuple 是 Scala Tuple2

just learned 这样的方法将在 Guava 21 中得到 Java-8 支持(耶!),但这听起来还需要 6 个月的时间。有谁知道今天可能实施此功能的任何现有图书馆(等)?

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

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

由于我还没有找到这样的收藏家图书馆,所以我将分享我对我需要的特定图书馆的第一次尝试。这里没有风吹草动! (例如处理或合并重复键。)

请随时提出改进建议。

/**
 * 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();
        }
    };
}

您不需要为此收集器编写匿名 class。您可以使用 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);
}

或者,如果您不介意先将结果收集到可变映射中,然后再将数据复制到不可变映射中,则可以结合使用 built-in toMap 收集器和 collectingAndThen:

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