嵌套分组用于具有内部ImmutableList的地图?

时间:2016-10-25 00:25:16

标签: java java-8 java-stream

我有以下几点:

Map<String, Map<String, List<SomeClass>>> someMap = 
    .... (streams and filtering, etc.) 
    .collect(Collectors.groupingBy(
       x -> getSomeComputedAttribute(x),
       Collectors.groupingBy(x -> getSomeOtherComputedAttribute(x));

到目前为止,这工作正常 - 我得到了正确的值,但问题是我需要将List转换为ImmutableList。有什么简单的方法可以做到这一点?

2 个答案:

答案 0 :(得分:3)

至于pointed out by Louis Wasserman,最简单的解决方案是使用内置收集器收集到List,并在后处理步骤中将收集的元素传输到ImmutableList:< / p>

Map<String, Map<String, List<SomeClass>>> someMap = 
    /* your stream operation */
    .collect(groupingBy(x -> getSomeComputedAttribute(x),
        groupingBy(x -> getSomeOtherComputedAttribute(x),
                   collectingAndThen(toList(), ImmutableList::copyOf))));

这当然会有复制整个列表内容的轻微性能缺陷。

天然解决方案将是基于构建器的收集器,例如

public static <T> Collector<T,?,List<T>> toImmutableList() {
    return Collector.of(
        ImmutableList::<T>builder,
        ImmutableList.Builder::add,
        (b1,b2) -> b1.addAll(b2.build()),
        ImmutableList.Builder::build);
}

并像

一样使用它
Map<String, Map<String, List<SomeClass>>> someMap = 
    /* your stream operation */
    .collect(groupingBy(x -> getSomeComputedAttribute(x),
        groupingBy(x -> getSomeOtherComputedAttribute(x), toImmutableList())));

但令人惊讶的是,这不会获得任何性能提升,因为在几乎所有情况下构建ImmutableList时仍会复制构建器的内容,因为它只会共享其内部数组(如果收集的数量)元素与数组的容量完全匹配。

不过,未来它可能会获得更新的Guava库的优势......

或者,您可以重新考虑它是否真的必须是不可变列表的Guava实现。您可以通过以下方式获得不可复制的列表而无需复制步骤:

Map<String, Map<String, List<SomeClass>>> someMap = 
    /* your stream operation */
    .collect(groupingBy(x -> getSomeComputedAttribute(x),
        groupingBy(x -> getSomeOtherComputedAttribute(x),
                   collectingAndThen(toList(), Collections::unmodifiableList))));

答案 1 :(得分:2)

如果你被限制在一个Java 8之前的番石榴 - 一个即将推出 - 那么可能最简单的解决方法(而不是一个坏的,老实说)collectingAndThen(toList(), ImmutableList::copyOf)