net.pincette.rs.Reducer Maven / Gradle / Ivy
package net.pincette.rs;
import static java.util.Optional.ofNullable;
import static net.pincette.util.Util.rethrow;
import static net.pincette.util.Util.tryToDo;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Flow.Publisher;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* Functions to reduce a publisher and return the result as a {@link
* java.util.concurrent.CompletionStage}.
*
* @author Werner Donné
* @since 1.1
*/
public class Reducer {
private Reducer() {}
/**
* Runs consumer for each emitted value.
*
* @param publisher the given publisher.
* @param consumer the consumer function.
* @param the value type of the publisher.
* @return The completion stage.
* @since 1.4.1
*/
public static CompletionStage forEach(
final Publisher publisher, final Consumer consumer) {
final CompletableFuture future = new CompletableFuture<>();
publisher.subscribe(
new LambdaSubscriber<>(
consumer::accept, () -> future.complete(null), future::completeExceptionally));
return future;
}
/**
* Runs consumer for each emitted value and makes it synchronous.
*
* @param publisher the given publisher.
* @param consumer the consumer function.
* @param the value type of the publisher.
* @since 1.4.1
*/
public static void forEachJoin(final Publisher publisher, final Consumer consumer) {
forEach(publisher, consumer).toCompletableFuture().join();
}
/**
* Accumulates all the values emitted by the publisher into a new value.
*
* @param publisher the given publisher.
* @param identity the function to produce the initial accumulated value.
* @param accumulator the function to accumulate all the values.
* @param the value type of the publisher.
* @param the value type of the result.
* @return The completion stage with the result.
* @since 1.1
*/
public static CompletionStage reduce(
final Publisher publisher,
final Supplier identity,
final BiFunction accumulator) {
final CompletableFuture future = new CompletableFuture<>();
final State state = new State<>(identity.get());
publisher.subscribe(
new LambdaSubscriber<>(
value ->
tryToDo(
() -> state.set(accumulator.apply(state.value, value)),
e -> {
future.completeExceptionally(e);
rethrow(e);
}),
() -> future.complete(state.value),
future::completeExceptionally));
return future;
}
/**
* Accumulates all the values emitted by the publisher by combining them.
*
* @param publisher the given publisher.
* @param accumulator the associative function that combines the values.
* @param the value type.
* @return The completion stage with the result. The optional will be empty when the publisher
* didn't emit any values before completing.
* @since 1.1
*/
public static CompletionStage> reduce(
final Publisher publisher, final BinaryOperator accumulator) {
return reduce(
publisher,
() -> new State(null),
(state, value) ->
state.set(state.value != null ? accumulator.apply(state.value, value) : value))
.thenApply(result -> ofNullable(result.value));
}
/**
* Accumulates all the values emitted by the publisher into a new value and makes it synchronous.
*
* @param publisher the given publisher.
* @param identity the function to produce the initial accumulated value.
* @param accumulator the function to accumulate all the values.
* @param the value type of the publisher.
* @param the value type of the result.
* @return The completion stage with the result.
* @since 1.4.1
*/
public static U reduceJoin(
final Publisher publisher,
final Supplier identity,
final BiFunction accumulator) {
return reduce(publisher, identity, accumulator).toCompletableFuture().join();
}
/**
* Accumulates all the values emitted by the publisher by combining them and makes it synchronous.
*
* @param publisher the given publisher.
* @param accumulator the associative function that combines the values.
* @param the value type.
* @return The completion stage with the result. The optional will be empty when the publisher
* didn't emit any values before completing.
* @since 1.4.1
*/
public static Optional reduceJoin(
final Publisher publisher, final BinaryOperator accumulator) {
return reduce(publisher, accumulator).toCompletableFuture().join();
}
private static class State {
private T value;
private State(final T value) {
this.value = value;
}
private State set(final T value) {
this.value = value;
return this;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy