I\'m starting with the Stream API in Java 8.
Here is my Person object I use:
public class Person {
private String firstName;
private String last
Without third-party libraries you may create a universal collector which combines the results of any number of specified collectors into single Object[]
array:
/**
* Returns a collector which combines the results of supplied collectors
* into the Object[] array.
*/
@SafeVarargs
public static Collector multiCollector(
Collector... collectors) {
@SuppressWarnings("unchecked")
Collector[] cs = (Collector[]) collectors;
return Collector. of(
() -> Stream.of(cs).map(c -> c.supplier().get()).toArray(),
(acc, t) -> IntStream.range(0, acc.length).forEach(
idx -> cs[idx].accumulator().accept(acc[idx], t)),
(acc1, acc2) -> IntStream.range(0, acc1.length)
.mapToObj(idx -> cs[idx].combiner().apply(acc1[idx], acc2[idx])).toArray(),
acc -> IntStream.range(0, acc.length)
.mapToObj(idx -> cs[idx].finisher().apply(acc[idx])).toArray());
}
For your concrete problem you'll also need a filtering()
collector (which will be added in JDK-9, see JDK-8144675):
public static Collector filtering(
Predicate super T> filter, Collector downstream) {
BiConsumer accumulator = downstream.accumulator();
Set characteristics = downstream.characteristics();
return Collector.of(downstream.supplier(), (acc, t) -> {
if(filter.test(t)) accumulator.accept(acc, t);
}, downstream.combiner(), downstream.finisher(),
characteristics.toArray(new Collector.Characteristics[characteristics.size()]));
}
Now you can build a collector which will generate the final result:
Collector collector =
multiCollector(
filtering(p -> p.getFirstName().equals("John"), counting()),
collectingAndThen(mapping(Person::getAge,
maxBy(Comparator.naturalOrder())), Optional::get),
collectingAndThen(mapping(Person::getHeight,
minBy(Comparator.naturalOrder())), Optional::get),
averagingDouble(Person::getWeight));
Object[] result = personsList.stream().collect(collector);
System.out.println(Arrays.toString(result));