Add prefix and suffix to Collectors.joining() only if there are multiple items present
Yes, this is possible using a custom Collector
instance that will use an anonymous object with a count of items in the stream and an overloaded toString()
method:
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();
}
Explanation
Collector
interface has the following methods:
public interface Collector<T,A,R> {
Supplier<A> supplier();
BiConsumer<A,T> accumulator();
BinaryOperator<A> combiner();
Function<A,R> finisher();
Set<Characteristics> characteristics();
}
I will omit the last method as it is not relevant for this example.
There is a collect()
method with the following signature:
<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);
and in our case it would resolve to:
<Object> Object collect(Supplier<Object> supplier,
BiConsumer<Object, ? super String> accumulator,
BiConsumer<Object, Object> combiner);
- In the
supplier
, we are using an instance ofStringJoiner
(basically the same thing thatCollectors.joining()
is using). - In the
accumulator
, we are usingStringJoiner::add()
but we increment the count as well - In the
combiner
, we are usingStringJoiner::merge()
and add the count to the accumulator - Before returning from
format()
function, we need to calltoString()
method to wrap our accumulatedStringJoiner
instance in[]
(or leave it as is is, in case of a single-element stream
The case for an empty case could also be added, I left it out in order not to make this collector more complicated.