【问题标题】:Java 8 collector for Guava Immutable Table用于 Guava 不可变表的 Java 8 收集器
【发布时间】:2016-08-16 22:51:18
【问题描述】:

用例:
通过返回ImmutableTable 类型{R,C,V} 的方法处理字符串列表。比如ImmutableTable of {Integer,String,Boolean} process(String item){...}

收集结果,即合并所有结果并返回ImmutableTable。有没有办法实现它?

当前实现(按照 Bohemian 的建议):

如何使用并行流?下面的代码中是否存在任何并发问题?使用并行流,我在 tableBuilder.build() 上获得“索引 1800 处的 NullPointerException”,但与流一起工作正常。

ImmutableTable<Integer, String, Boolean> buildData() {   

  // list of 4 AwsS3KeyName   
listToProcess.parallelStream() 

  //Create new instance via Guice dependency injection 
.map(s3KeyName -> ProcessorInstanceProvider.get()    
.fetchAndBuild(s3KeyName)) 
.forEach(tableBuilder::putAll); 

 return tableBuilder.build(); }

虽然下面的代码适用于流以及并行流。但是由于行和列的重复条目,ImmutableBuild 失败了。合并表时防止重复的最佳方法是什么?

public static <R, C, V> Collector<ImmutableTable<R, C, V>,     
ImmutableTable.Builder<R, C, V>, ImmutableTable<R, C, V>>   
toImmutableTable() 
{ 
return Collector.of(ImmutableTable.Builder::new, 
ImmutableTable.Builder::putAll, (builder1, builder2) -> 
builder1.putAll(builder2.build()), ImmutableTable.Builder::build); }

编辑: 如果在合并不同的表时 ImmutableTable.Builder 中有任何重复条目,则它会失败,

试图通过将 ImmutableTables 放入 HashBasedTable 来避免错误

  ImmutableTable.copyOf(itemListToProcess.parallelStream()
            .map(itemString ->
           ProcessorInstanceProvider.get()
                    .buildImmutableTable(itemString))
                    .collect(
                            Collector.of(
                                    HashBasedTable::create,
                                    HashBasedTable::putAll,
                                    (a, b) -> {
                                        a.putAll(b);
                                        return a;
                                    }));
  )

但我收到运行时异常“原因:java.lang.IllegalAccessError:试图访问类 com.google.common.collect.AbstractTable”。

我们如何使用 HashBasedTable 作为 Accumulator 来收集 ImmutablesTables,因为 HashBasedTable 会用最新的条目覆盖现有条目,并且如果我们尝试放置重复条目并返回聚合的 Immutable 表也不会失败。

【问题讨论】:

标签: java java-8 guava immutable-collections


【解决方案1】:

从 Guava 21 开始你可以使用ImmutableTable.toImmutableTablecollector。

public ImmutableTable<Integer, String, Boolean> processList(List<String> strings) {
    return strings.stream()
            .map(this::processText)
            .flatMap(table -> table.cellSet().stream())
            .collect(ImmutableTable.toImmutableTable(
                    Table.Cell::getRowKey,
                    Table.Cell::getColumnKey,
                    Table.Cell::getValue,
                    (b1, b2) -> b1 && b2 // You can ommit merge function!
            ));
}

private ImmutableTable<Integer, String, Boolean> processText(String text) {
    return ImmutableTable.of(); // Whatever
}

【讨论】:

    【解决方案2】:

    这应该可行:

    List<String> list; // given a list of String
    
    ImmutableTable result = list.parallelStream()
        .map(processor::process) // converts String to ImmutableTable
        .collect(ImmutableTable.Builder::new, ImmutableTable.Builder::putAll,
            (a, b) -> a.putAll(b.build())
        .build();
    

    这种减少是线程安全的。


    或者使用HashBasedTable作为中间数据结构:

    ImmutableTable result = ImmutableTable.copyOf(list.parallelStream()
        .map(processor::process) // converts String to ImmutableTable
        .collect(HashBasedTable::create, HashBasedTable::putAll, HashBasedTable::putAll));
    

    【讨论】:

    • 使用并行流怎么样?您在这里看到任何并发问题吗? public ImmutableTable fetch() { listToProcess.parallelStream() // 4 个 AwsS3KeyName 的列表 .map(s3KeyName -> ProcessorInstanceProvider.get() //通过 Guice 依赖注入创建新实例 .build(s3KeyName)) .forEach(tableBuilder::putAll);返回 tableBuilder.build(); }
    • 文档没有说ImmutableTable 是线程安全的,但是请查看线程安全的更改代码(现在也只有一行:))
    • 非常感谢您提供此解决方案。由于重复而构建失败,请告知防止重复的最佳方法是什么?看来我将不得不使用 HashBasedTable。
    • @sidss 复制了什么?
    • 当相同的行列条目存在于两个不同的表中时。所以当 ImmutableTable.build 被调用并且当有任何重复时失败。所以它似乎而不是 ImmutableTable.Builder 我将不得不使用 HashBasedTable。
    【解决方案3】:

    您应该能够通过使用Collector.of 静态工厂方法创建适当的Collector 来做到这一点:

    ImmutableTable<R, C, V> table =
        list.stream()
            .map(processor::process)
            .collect(
                Collector.of(
                    () -> new ImmutableTable.Builder<R, C, V>(),
                    (builder, table1) -> builder.putAll(table1),
                    (builder1, builder2) ->
                        new ImmutableTable.Builder<R, C, V>()
                            .putAll(builder1.build())
                            .putAll(builder2.build()),
                    ImmutableTable.Builder::build));
    

    【讨论】:

    • 我认为您可以为 Supplier(ImmutableTable.Builder::new) 和 BiConsumer (ImmutableTable.Builder::putAll) 使用方法引用。
    • 我不相信你可以:我试过ImmutableTable.Builder::new,但它无法推断类型。
    • 可以通过重用其中一个构建器来优化组合器。例如:builder1.putAll(builder2.build())
    • 此外,如果您将其全部包装到一个函数中,您可以为供应商和累加器使用方法引用。例如:public static &lt;R, C, V&gt; Collector&lt;ImmutableTable&lt;R, C, V&gt;, ImmutableTable.Builder&lt;R, C, V&gt;, ImmutableTable&lt;R, C, V&gt;&gt; toImmutableTable() { return Collector.of(ImmutableTable.Builder::new, ImmutableTable.Builder::putAll, (builder1, builder2) -&gt; builder1.putAll(builder2.build()), ImmutableTable.Builder::build); }
    • 适用于流和并行流。但是由于行和列的重复条目,ImmutableBuild 失败了。看来我将不得不使用 HashBasedTable 来防止重复。有没有其他方法可以防止 Immutable.copyof(hashBasedTable)。
    猜你喜欢
    • 1970-01-01
    • 2016-12-30
    • 2017-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-11
    相关资源
    最近更新 更多