Java 8 个 Guava 不可变收集器 Table

Java 8 collector for Guava Immutable Table

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

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

当前实施(如 Bohemian 所建议):

使用并行流怎么样?下面的代码有并发问题吗?使用并行流,我在 tableBuilder.build() 上获得 "NullPointerException at index 1800",但可以正常使用流。

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 由于行和列的重复条目而失败。合并 table 时防止重复的最佳方法是什么?

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); }

编辑: 如果在合并不同的 table 时 ImmutableTable.Builder 中有任何重复的条目,那么它将失败,

试图通过将 Immutable表放入 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;
                                    }));
  )

但我收到运行时异常 "Caused by: java.lang.IllegalAccessError: tried to access class com.google.common.collect.AbstractTable"。

我们如何使用 HashBasedTable 作为累加器来收集 ImmutablesTables,因为 HashBasedTable 会用最新的条目覆盖现有条目,并且如果我们尝试放置重复条目也不会失败,并且 return聚合 Immutable table.

这应该有效:

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));

您应该能够通过使用 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));

从 Guava 21 开始,您可以使用 ImmutableTable.toImmutableTable 收集器。

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
}