我有一串弦:
Stream<String> stream = ...;
我想构造一个字符串,用,
作为分隔符连接这些项。
stream.collect(Collectors.joining(","));
现在,我只想在有多个项目的情况下,在输出中添加前缀[
和后缀]
。
a
[a,b]
[a,b,c]
如果不先将Stream<String>
具体化为List<String>
,然后再检查List.size() == 1
,是否可以完成此操作?
public String format(Stream<String> stream) {
List<String> list = stream.collect(Collectors.toList());
if (list.size() == 1) {
return list.get(0);
}
return "[" + list.stream().collect(Collectors.joining(",")) + "]";
}
首先将流转换为列表,然后再转换为流,以便能够应用Collectors.joining(",")
,这感觉很奇怪。我认为循环通过整个流(这是在Collectors.toList()
期间完成的),只是为了发现是否存在一个或多个项,这是次优的。
我可以实现我自己的Collector<String, String>
来计算给定项的数量,然后使用这个计数,但是我想知道是否有更直接的方法。
这个问题故意忽略了流为空的情况。
3条答案
按热度按时间np8igboo1#
是的,这可以通过使用一个定制的
Collector
示例来实现,该示例将使用一个匿名对象,该对象具有流中的项目计数和一个重载的toString()
方法:解释
Collector
接口有以下方法:我将省略最后一个方法,因为它与本例无关。
有一个具有以下签名的
collect()
方法:就我国而言,它将决定:
supplier
中,我们使用了StringJoiner
的一个示例(基本上与Collectors.joining()
使用的相同)。accumulator
中,我们使用StringJoiner::add()
,但也会递增计数combiner
中,我们使用StringJoiner::merge()
并将计数添加到累加器format()
函数返回之前,我们需要调用toString()
方法,将累积的StringJoiner
示例 Package 在[]
中(或者在单元素流的情况下,保持原样一个空箱子的箱子也可以加进去,我把它留了出来,为了不让这个收集器变得更复杂。
euoag5mw2#
已经有一个公认的答案,我也投了赞成票。
我仍然想提供另一种可能的解决方案。可能是因为它有一个要求:
Stream<String> stream
的stream.spliterator()
必须是Spliterator.SIZED
。如果这适用于您的情况,您也可以使用此解决方案:
根据JavaDoc,
Spliterator.getExactSizeIfKnown()
"如果Spliterator
是SIZED
,则返回estimateSize()
,否则返回-1
"。如果Spliterator
是SIZED
,则"在遍历或拆分之前的estimateSize()
表示有限大小,在没有结构源修改的情况下,表示完整遍历将遇到的元素数目的精确计数。由于"大多数用于集合的拆分器,覆盖
Collection
的所有元素,报告此特征"(SIZED
的JavaDoc中的API注解),这可能是所需的 * 直接方式 *。如果
Stream
为空,我们可以立即返回一个空的String
;如果Stream
只有一个String
,则不需要创建一个StringJoiner
,也不需要将String
复制到StringJoiner
,我们直接返回单个String
。cngwdvgl3#
我知道我迟到了,但我最近也遇到了同样的问题,我想也许值得记录一下我是如何解决这个问题的。
虽然公认的解决方案确实有效,但我认为它比实际需要的要复杂得多,使其难以阅读和理解。与定义一个
Object
实现,然后分离访问和修改所述对象状态的累加器和组合器函数相反,为什么不定义自己的收集器呢?在上面提出的问题中,这可以通过以下方式实现:原理是一样的,你有一个计数器,每当元素被添加到
StringJoiner
时,它就会递增。基于添加的元素总数,finisher
决定StringJoiner
的结果是否应该用方括号括起来。这是不言而喻的,但是你甚至可以定义一个特定于这个实现的单独的类。允许它在整个代码库中使用。您甚至可以更进一步,使它更通用以支持更广泛的输入类型,添加自定义前缀/后缀参数,等等。说到使用,只需将收集器的示例传递给Stream
的collect
方法: