我需要一个与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地狱,我仍然在翻找它......
答案 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()
,然后手动执行完成转换。阅读霍尔格的答案,似乎这种方法已经存在。