扩展现有的流收集器实例

时间:2017-07-28 14:40:13

标签: java java-8 java-stream

我需要一个与Collectors.toSet()几乎相同的收藏家,但需要一个自定义修整器。我希望能够做到这样的事情:

myCollector = Collectors.toSet();
myCollector.setFinisher(myCustomFinisher);

并且已经完成,但这似乎不可能。我能看到的唯一选择是它本质上使用Collectors.toSet()重新创建Collector.of(),这不是很干。

是否可以采用现有的收集器并按上述方法对其进行修改?

修改

一些答案​​建议如下:

  Collector<T, ?, Set<T>> toSet = Collectors.toSet();
  return Collector.of(
     toSet.supplier(),
     toSet.accumulator(),
     toSet.combiner(),
     yourFinisher,
     toSet.characteristics());

然而,我的自定义修整器实际上并没有返回一个Set;它使用累积的集合返回其他东西。它正在这样做的事实让我陷入了Generics地狱,我仍然在翻找它......

3 个答案:

答案 0 :(得分:11)

这正是collectingAndThen(collector,finisher)所做的。

自定义修整器不会替换旧的修整器(如果有),但会与它结合使用(如oldFinisher.andThen(newFinisher)),但toSet()的当前实现没有修整器(身份修整器)反正。

所以你需要做的就是collectingAndThen(toSet(),myCustomFinisher) ......

答案 1 :(得分:4)

这基本上是toSet的实现:

 Collector.of(
            HashSet::new,
            Set::add,
            (left, right) -> {
                left.addAll(right);
                return left;
            });

您所要做的就是添加UNORDERED特征和您的终结者。说实话,看起来相当微不足道。 看看霍尔格的答案。

答案 2 :(得分:3)

从字面上理解你的问题的标题,你无法通过“扩展”返回Collector的{​​{1}}来实现你想要的,因为Set的第三个泛型类型参数指定了“还原操作的结果类型“,因此Collector永远不能是Collector<?,?,R>的子类,除非R实现Collector<?,?,Set>

我不知道你想用Set作为整理函数做什么,我也不知道Set中元素的类型,所以让我们假设,为了简单,您要通过Set进行流式传输,并希望通过返回结果String的大小来检查流中唯一String的数量。

Set<String>的类型必须为Collector,因此您无法绕过此声明(您希望确定唯一Collector<String, ?, Integer>的数量String无关紧要,因此第二个参数可以是Set<String>)。

现在,您自然希望利用?。但是怎么样? Collectors.toSet()有4个功能,供应商,累加器,组合器和修整器。从这4个中,您似乎可以使用Collector返回的Collector的前3个。现在这里是擦除:Collectors.toSet()的返回类型实际上是Collectors.toSet(),第二个类型参数Collector<T, ?, Set<T>>表示累积类型,这是问题所在。用非通用术语解释这一点:你无法知道?如何在内部积累元素。您只知道整理函数将返回Collector。但是,这并不一定意味着项目将在Set中累积。如您所知,Set可以累积Collector中的项目,只有在完成阶段才能从List的内容中创建Set。另一方面,自定义List的完成功能(计算Collector的大小)需要Set作为输入值,但Set返回Collector无法保证将元素累积到Collectors.toSet()

不幸的是,这意味着,如果您要创建自定义Set,将流元素累积到Collector并在完成阶段返回此Set的大小(或做Set所做的其他事情,Set返回的colletor实际上没用,因为Collectors.toSet()supplier和{{1}都是三个accumulator的参数取决于累积类型,combiner不知道。

因此,在我看来,最可行的解决方案是创建一个帮助方法,首先使用Collector.of(Supplier, BiConsumer, BinaryOperator, Function, Collector.Characteristics)将流元素收集到Collectors.toSet(),然后手动执行完成转换。阅读霍尔格的答案,似乎这种方法已经存在。