2 回答
TA贡献1880条经验 获得超4个赞
是的,这可以使用自定义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();
}
解释
Collector 接口有以下方法:
public interface Collector<T,A,R> {
Supplier<A> supplier();
BiConsumer<A,T> accumulator();
BinaryOperator<A> combiner();
Function<A,R> finisher();
Set<Characteristics> characteristics();
}
我将省略最后一个方法,因为它与本示例无关。
有一个collect()具有以下签名的方法:
<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);
在我们的情况下,它将解决:
<Object> Object collect(Supplier<Object> supplier,
BiConsumer<Object, ? super String> accumulator,
BiConsumer<Object, Object> combiner);
在 中
supplier
,我们使用了一个实例StringJoiner
(与Collectors.joining()
使用的东西基本相同)。在 中
accumulator
,我们正在使用StringJoiner::add()
但我们也增加了计数在 中
combiner
,我们正在使用StringJoiner::merge()
并将计数添加到累加器在从
format()
函数返回之前,我们需要调用toString()
方法来包装我们累积的StringJoiner
实例[]
(或者保持原样,在单元素流的情况下)
也可以添加一个空箱子的箱子,为了不让这个收藏家更复杂,我把它省略了。
TA贡献1871条经验 获得超8个赞
已经有一个可以接受的答案,我也赞成。
我仍然想提供可能的另一种解决方案。可能是因为它有一个要求:
the stream.spliterator()ofStream<String> stream需要是Spliterator.SIZED。
如果这适用于您的情况,您也可以使用此解决方案:
public String format(Stream<String> stream) {
Spliterator<String> spliterator = stream.spliterator();
StringJoiner sj = spliterator.getExactSizeIfKnown() == 1 ?
new StringJoiner("") :
new StringJoiner(",", "[", "]");
spliterator.forEachRemaining(sj::add);
return sj.toString();
}
根据JavaDoc Spliterator.getExactSizeIfKnown() “estimateSize()如果Spliterator是SIZED,则返回,否则返回-1。” 如果 aSpliterator是,SIZED则“estimateSize()在遍历或拆分之前表示有限大小,在没有结构源修改的情况下,表示完整遍历将遇到的元素数量的精确计数。”
由于“大多数 Spliterators for Collections,涵盖了Collection报告此特征的所有元素”(JavaDoc 中的 API 注释SIZED),这可能是所需的更直接的方式。
编辑:
如果Stream是空的,我们可以立即返回一个空String的。如果Stream只有一个String,则无需创建一个StringJoiner并将其复制String到它。我们String直接返回单曲。
public String format(Stream<String> stream) {
Spliterator<String> spliterator = stream.spliterator();
if (spliterator.getExactSizeIfKnown() == 0) {
return "";
}
if (spliterator.getExactSizeIfKnown() == 1) {
AtomicReference<String> result = new AtomicReference<String>();
spliterator.tryAdvance(result::set);
return result.get();
}
StringJoiner result = new StringJoiner(",", "[", "]");
spliterator.forEachRemaining(result::add);
return result.toString();
}
添加回答
举报