The most common way to solve such problems is to combine the result of several collectors into one.
Using the jOOL library, you can get the following:
Content content = Seq.seq(contentList) .collect( Collectors.mapping(Content::getA, Collectors.joining(", ")), Collectors.mapping(Content::getB, Collectors.joining(", ")), Collectors.mapping(Content::getC, Collectors.joining(", ")) ).map(Content::new);
This creates Seq from the input list and combines the 3 given collectors to create Tuple3 , which is simply a holder for 3 values. Then these 3 values ββare displayed in Content using the new Content(a, b, c) constructor. The collectors themselves simply map each Content to its value a , b or c and combine the results together, separating them with ", " .
Without third-party help, we could create our own combiner collector (this is based on StreamEx pairing , which does the same for 2 collectors). It takes 3 collectors as arguments and performs a finisher operation based on the result of 3 collected values.
public interface TriFunction<T, U, V, R> { R apply(T t, U u, V v); } public static <T, A1, A2, A3, R1, R2, R3, R> Collector<T, ?, R> combining(Collector<? super T, A1, R1> c1, Collector<? super T, A2, R2> c2, Collector<? super T, A3, R3> c3, TriFunction<? super R1, ? super R2, ? super R3, ? extends R> finisher) { final class Box<A, B, C> { A a; B b; C c; Box(A a, B b, C c) { this.a = a; this.b = b; this.c = c; } } EnumSet<Characteristics> c = EnumSet.noneOf(Characteristics.class); c.addAll(c1.characteristics()); c.retainAll(c2.characteristics()); c.retainAll(c3.characteristics()); c.remove(Characteristics.IDENTITY_FINISH); return Collector.of( () -> new Box<>(c1.supplier().get(), c2.supplier().get(), c3.supplier().get()), (acc, v) -> { c1.accumulator().accept(acc.a, v); c2.accumulator().accept(acc.b, v); c3.accumulator().accept(acc.c, v); }, (acc1, acc2) -> { acc1.a = c1.combiner().apply(acc1.a, acc2.a); acc1.b = c2.combiner().apply(acc1.b, acc2.b); acc1.c = c3.combiner().apply(acc1.c, acc2.c); return acc1; }, acc -> finisher.apply(c1.finisher().apply(acc.a), c2.finisher().apply(acc.b), c3.finisher().apply(acc.c)), c.toArray(new Characteristics[c.size()]) ); }
and finally use it with
Content content = contentList.stream().collect(combining( Collectors.mapping(Content::getA, Collectors.joining(", ")), Collectors.mapping(Content::getB, Collectors.joining(", ")), Collectors.mapping(Content::getC, Collectors.joining(", ")), Content::new ));