【问题标题】:Java - Are there any Stream Collectors that return ImmutableMap? [duplicate]Java - 是否有任何返回 ImmutableMap 的流收集器? [复制]
【发布时间】:2015-12-29 06:49:49
【问题描述】:

我发现自己想要一个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(耶!)但这听起来还需要 6 个月的时间。有谁知道今天可能实现此功能的任何现有库(等)?

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

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

【问题讨论】:

  • 我很惊讶你没有在互联网上看到任何东西。在流行的搜索引擎中搜索“guava java 8 collector”会返回很多直接可用的代码,包括直接在 Guava 项目中的结果(作为问题)。
  • 我们为此提供了collectingAndThen()。
  • ImmutableMultimap 上的问题的答案确实回答了我的直接问题。然而,那里的解决方案或我现在在网上找到的解决方案似乎都没有包含一套完美的功能来处理ImmutableMap——它们缺乏合并重复键的能力和/或不抛出IllegalStateException (遵循Collectors 设定的约定)
  • 从 Guava 21 开始就内置了ImmutableMap.toImmutableMapcollector。
  • 查看answer 了解如何使用 Guava 的 toImmutableMap() 收集器的示例。

标签: java-8 guava


【解决方案1】:

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

【讨论】:

  • 完美 :-) 我没想到要查看界面本身。我绝对更喜欢Collector.of 形式,因为这将成为一个未来用途未知的实用函数(并且以后很难追踪内存流失的来源。)
  • Guava 现在为其收集类型提供收集器,例如ImmutableList.toImmutableMap().
  • 如果你不想使用 Guava,你可以用 Map result = list.stream() .collect(collectingAndThen( toMap( tuple -> tuple._1 (), 元组 -> 元组._2()), Collections::unmodifiableMap));
  • 您应该指出第二种方法不保持问题中要求的原始迭代顺序。
  • 我更喜欢ImmutableMap::&lt;K, V&gt;builder 而不是ImmutableMap.Builder&lt;K, V&gt;::new
【解决方案2】:

由于我还没有找到这样一个收藏家图书馆,所以我将分享我对特定收藏家的第一次破解。这里没有花里胡哨! (例如处理或合并重复键。)

请随时提出改进建议。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-22
    • 2011-04-30
    • 2016-02-29
    • 1970-01-01
    • 2019-03-26
    • 2014-05-03
    • 2020-10-11
    相关资源
    最近更新 更多