Joh*_*Doe 6 java string java-8 java-stream
我有一些字符串:
Stream<String> stream = ...;
Run Code Online (Sandbox Code Playgroud)
我想构造一个字符串,将这些项目与,分隔符连接起来。我这样做如下:
stream.collect(Collectors.joining(","));
Run Code Online (Sandbox Code Playgroud)
现在,仅在有多个项目的情况下,才想在此输出中添加前缀[和后缀]。例如:
a[a,b][a,b,c]可以在不首先实现Stream<String>到a 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(",")) + "]";
}
Run Code Online (Sandbox Code Playgroud)
首先将流转换为列表,然后再次将其转换为流以能够应用,这感觉很奇怪Collectors.joining(",")。我认为遍历整个流(在期间完成Collectors.toList())只是发现是否存在一项或多项是次优的。
我可以实现自己的方法Collector<String, String>,对给定项目的数量进行计数,然后再使用该计数。但是我想知道是否有更直接的方法。
当流为空时,此问题有意忽略了这种情况。
是的,这可以通过使用自定义Collector实例来实现,该实例将使用匿名对象以及流中的项目计数和重载toString()方法:
public String format(Stream<String> stream) {
return stream.collect(
() -> new Object() {
StringJoiner stringJoiner = new StringJoiner(",");
int count;
@Override
public String toString() {
return count == 1 ? stringJoiner.toString() : "[" + stringJoiner + "]";
}
},
(container, currentString) -> {
container.stringJoiner.add(currentString);
container.count++;
},
(accumulatingContainer, currentContainer) -> {
accumulatingContainer.stringJoiner.merge(currentContainer.stringJoiner);
accumulatingContainer.count += currentContainer.count;
}
).toString();
}
Run Code Online (Sandbox Code Playgroud)
Collector 界面具有以下方法:
public interface Collector<T,A,R> {
Supplier<A> supplier();
BiConsumer<A,T> accumulator();
BinaryOperator<A> combiner();
Function<A,R> finisher();
Set<Characteristics> characteristics();
}
Run Code Online (Sandbox Code Playgroud)
我将省略最后一个方法,因为它与本示例无关。
有一个collect()具有以下签名的方法:
<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);
Run Code Online (Sandbox Code Playgroud)
在我们的情况下,它将解决:
<Object> Object collect(Supplier<Object> supplier,
BiConsumer<Object, ? super String> accumulator,
BiConsumer<Object, Object> combiner);
Run Code Online (Sandbox Code Playgroud)
supplier,我们使用的实例StringJoiner(基本上与之相同Collectors.joining())。accumulator,我们正在使用,StringJoiner::add()但我们也会增加计数combiner,我们正在使用StringJoiner::merge()并将计数添加到累加器format()函数返回之前,我们需要调用toString()方法将累积的StringJoiner实例包装在其中[](或在单元素流的情况下保留原样)也可以添加一个空盒子的盒子,为了不使该收集器变得更加复杂,我将其省略。