/*
 * Copyright 2017-2020 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.micronaut.core.util;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

Utility methods for working with streams.
Author:James Kleeh
Since:1.0
/** * Utility methods for working with streams. * * @author James Kleeh * @since 1.0 */
public class StreamUtils {
A collector that returns all results that are the maximum based on the provided comparator.
Params:
  • comparator – The comparator to order the items in the stream
  • downstream – Which collector to use to combine the results
Type parameters:
  • <T> – The type of objects being streamed
  • <A> – The mutable accumulation type of the reduction operation
  • <D> – The result type of the reduction operation
Returns:A new collector to provide the desired result
/** * A collector that returns all results that are the maximum based on the provided comparator. * * @param comparator The comparator to order the items in the stream * @param downstream Which collector to use to combine the results * @param <T> The type of objects being streamed * @param <A> The mutable accumulation type of the reduction operation * @param <D> The result type of the reduction operation * @return A new collector to provide the desired result */
public static <T, A, D> Collector<T, ?, D> maxAll(Comparator<? super T> comparator, Collector<? super T, A, D> downstream) { Supplier<A> downstreamSupplier = downstream.supplier(); BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); BinaryOperator<A> downstreamCombiner = downstream.combiner();
Container used to hold the accumulator and object
/** * Container used to hold the accumulator and object */
class Container { A acc; T obj; boolean hasAny;
Constructor.
Params:
  • acc – accumulator
/** * Constructor. * @param acc accumulator */
Container(A acc) { this.acc = acc; } } Supplier<Container> supplier = () -> new Container(downstreamSupplier.get()); BiConsumer<Container, T> accumulator = (acc, t) -> { if (!acc.hasAny) { downstreamAccumulator.accept(acc.acc, t); acc.obj = t; acc.hasAny = true; } else { int cmp = comparator.compare(t, acc.obj); if (cmp > 0) { acc.acc = downstreamSupplier.get(); acc.obj = t; } if (cmp >= 0) { downstreamAccumulator.accept(acc.acc, t); } } }; BinaryOperator<Container> combiner = (acc1, acc2) -> { if (!acc2.hasAny) { return acc1; } if (!acc1.hasAny) { return acc2; } int cmp = comparator.compare(acc1.obj, acc2.obj); if (cmp > 0) { return acc1; } if (cmp < 0) { return acc2; } acc1.acc = downstreamCombiner.apply(acc1.acc, acc2.acc); return acc1; }; Function<Container, D> finisher = acc -> downstream.finisher().apply(acc.acc); return Collector.of(supplier, accumulator, combiner, finisher); }
A collector that returns all results that are the minimum based on the provided comparator.
Params:
  • comparator – The comparator to order the items in the stream
  • downstream – Which collector to use to combine the results
Type parameters:
  • <T> – The type of objects being streamed
  • <A> – The mutable accumulation type of the reduction operation
  • <D> – The result type of the reduction operation
Returns:A new collector to provide the desired result
/** * A collector that returns all results that are the minimum based on the * provided comparator. * * @param comparator The comparator to order the items in the stream * @param downstream Which collector to use to combine the results * @param <T> The type of objects being streamed * @param <A> The mutable accumulation type of the reduction operation * @param <D> The result type of the reduction operation * @return A new collector to provide the desired result */
public static <T, A, D> Collector<T, ?, D> minAll(Comparator<? super T> comparator, Collector<? super T, A, D> downstream) { Supplier<A> downstreamSupplier = downstream.supplier(); BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); BinaryOperator<A> downstreamCombiner = downstream.combiner();
Container used to hold the accumulator and object
/** * Container used to hold the accumulator and object */
class Container { A acc; T obj; boolean hasAny;
Constructor.
Params:
  • acc – accumulator
/** * Constructor. * @param acc accumulator */
Container(A acc) { this.acc = acc; } } Supplier<Container> supplier = () -> new Container(downstreamSupplier.get()); BiConsumer<Container, T> accumulator = (acc, t) -> { if (!acc.hasAny) { downstreamAccumulator.accept(acc.acc, t); acc.obj = t; acc.hasAny = true; } else { int cmp = comparator.compare(t, acc.obj); if (cmp < 0) { acc.acc = downstreamSupplier.get(); acc.obj = t; } if (cmp <= 0) { downstreamAccumulator.accept(acc.acc, t); } } }; BinaryOperator<Container> combiner = (acc1, acc2) -> { if (!acc2.hasAny) { return acc1; } if (!acc1.hasAny) { return acc2; } int cmp = comparator.compare(acc1.obj, acc2.obj); if (cmp < 0) { return acc1; } if (cmp > 0) { return acc2; } acc1.acc = downstreamCombiner.apply(acc1.acc, acc2.acc); return acc1; }; Function<Container, D> finisher = acc -> downstream.finisher().apply(acc.acc); return Collector.of(supplier, accumulator, combiner, finisher); }
Params:
  • collectionFactory – The collection factory
Type parameters:
  • <T> – The type of the input elements
  • <A> – The accumulation type
Returns:An immutable collection
/** * @param collectionFactory The collection factory * @param <T> The type of the input elements * @param <A> The accumulation type * @return An immutable collection */
public static <T, A extends Collection<T>> Collector<T, A, Collection<T>> toImmutableCollection(Supplier<A> collectionFactory) { return Collector.of(collectionFactory, Collection::add, (left, right) -> { left.addAll(right); return left; }, Collections::unmodifiableCollection); }
Type parameters:
  • <T> – The type
Returns:An immutable collection
/** * @param <T> The type * @return An immutable collection */
public static <T> Collector<T, Collection<T>, Collection<T>> toImmutableCollection() { return toImmutableCollection(ArrayList::new); } }