All Downloads are FREE. Search and download functionalities are using the official Maven repository.

reactor.core.publisher.Flux Maven / Gradle / Ivy

/*
 * Copyright (c) 2011-2017 Pivotal Software Inc, All Rights Reserved.
 *
 * 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
 *
 *       http://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 reactor.core.publisher;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.LongConsumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.stream.Collector;
import java.util.stream.Stream;

import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import reactor.core.CoreSubscriber;
import reactor.core.Disposable;
import reactor.core.Exceptions;
import reactor.core.Fuseable;
import reactor.core.Scannable;
import reactor.core.publisher.FluxSink.OverflowStrategy;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Scheduler.Worker;
import reactor.core.scheduler.Schedulers;
import reactor.util.Logger;
import reactor.util.annotation.Nullable;
import reactor.util.concurrent.Queues;
import reactor.util.context.Context;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuple3;
import reactor.util.function.Tuple4;
import reactor.util.function.Tuple5;
import reactor.util.function.Tuple6;
import reactor.util.function.Tuples;

/**
 * A Reactive Streams {@link Publisher} with rx operators that emits 0 to N elements, and then completes
 * (successfully or with an error).
 *
 * 

* *

* *

It is intended to be used in implementations and return types. Input parameters should keep using raw * {@link Publisher} as much as possible. * *

If it is known that the underlying {@link Publisher} will emit 0 or 1 element, {@link Mono} should be used * instead. * *

Note that using state in the {@code java.util.function} / lambdas used within Flux operators * should be avoided, as these may be shared between several {@link Subscriber Subscribers}. * *

{@link #subscribe(CoreSubscriber)} is an internal extension to * {@link #subscribe(Subscriber)} used internally for {@link Context} passing. User * provided {@link Subscriber} may * be passed to this "subscribe" extension but will loose the available * per-subscribe @link Hooks#onLastOperator}. * * @param the element type of this Reactive Streams {@link Publisher} * * @author Sebastien Deleuze * @author Stephane Maldini * @author David Karnok * @author Simon Baslé * * @see Mono */ public abstract class Flux implements Publisher { // ============================================================================================================== // Static Generators // ============================================================================================================== /** * Build a {@link Flux} whose data are generated by the combination of the most recently published value from each * of the {@link Publisher} sources. *

* * * @param sources The {@link Publisher} sources to combine values from * @param combinator The aggregate function that will receive the latest value from each upstream and return the value * to signal downstream * @param type of the value from sources * @param The produced output after transformation by the given combinator * * @return a {@link Flux} based on the produced combinations */ @SafeVarargs public static Flux combineLatest(Function combinator, Publisher... sources) { return combineLatest(combinator, Queues.XS_BUFFER_SIZE, sources); } /** * Build a {@link Flux} whose data are generated by the combination of the most recently published value from each * of the {@link Publisher} sources. *

* * * @param sources The {@link Publisher} sources to combine values from * @param prefetch The demand sent to each combined source {@link Publisher} * @param combinator The aggregate function that will receive the latest value from each upstream and return the value * to signal downstream * @param type of the value from sources * @param The produced output after transformation by the given combinator * * @return a {@link Flux} based on the produced combinations */ @SafeVarargs public static Flux combineLatest(Function combinator, int prefetch, Publisher... sources) { if (sources.length == 0) { return empty(); } if (sources.length == 1) { Publisher source = sources[0]; if (source instanceof Fuseable) { return onAssembly(new FluxMapFuseable<>(from(source), v -> combinator.apply(new Object[]{v}))); } return onAssembly(new FluxMap<>(from(source), v -> combinator.apply(new Object[]{v}))); } return onAssembly(new FluxCombineLatest<>(sources, combinator, Queues.get(prefetch), prefetch)); } /** * Build a {@link Flux} whose data are generated by the combination of the most recently published value from each * of two {@link Publisher} sources. *

* * * @param source1 The first {@link Publisher} source to combine values from * @param source2 The second {@link Publisher} source to combine values from * @param combinator The aggregate function that will receive the latest value from each upstream and return the value * to signal downstream * @param type of the value from source1 * @param type of the value from source2 * @param The produced output after transformation by the given combinator * * @return a {@link Flux} based on the produced combinations */ @SuppressWarnings("unchecked") public static Flux combineLatest(Publisher source1, Publisher source2, BiFunction combinator) { return combineLatest(tuple -> combinator.apply((T1)tuple[0], (T2)tuple[1]), source1, source2); } /** * Build a {@link Flux} whose data are generated by the combination of the most recently published value from each * of three {@link Publisher} sources. *

* * * @param source1 The first {@link Publisher} source to combine values from * @param source2 The second {@link Publisher} source to combine values from * @param source3 The third {@link Publisher} source to combine values from * @param combinator The aggregate function that will receive the latest value from each upstream and return the value * to signal downstream * @param type of the value from source1 * @param type of the value from source2 * @param type of the value from source3 * @param The produced output after transformation by the given combinator * * @return a {@link Flux} based on the produced combinations */ public static Flux combineLatest(Publisher source1, Publisher source2, Publisher source3, Function combinator) { return combineLatest(combinator, source1, source2, source3); } /** * Build a {@link Flux} whose data are generated by the combination of the most recently published value from each * of four {@link Publisher} sources. *

* * * @param source1 The first {@link Publisher} source to combine values from * @param source2 The second {@link Publisher} source to combine values from * @param source3 The third {@link Publisher} source to combine values from * @param source4 The fourth {@link Publisher} source to combine values from * @param combinator The aggregate function that will receive the latest value from each upstream and return the value * to signal downstream * @param type of the value from source1 * @param type of the value from source2 * @param type of the value from source3 * @param type of the value from source4 * @param The produced output after transformation by the given combinator * * @return a {@link Flux} based on the produced combinations */ public static Flux combineLatest(Publisher source1, Publisher source2, Publisher source3, Publisher source4, Function combinator) { return combineLatest(combinator, source1, source2, source3, source4); } /** * Build a {@link Flux} whose data are generated by the combination of the most recently published value from each * of five {@link Publisher} sources. *

* * * @param source1 The first {@link Publisher} source to combine values from * @param source2 The second {@link Publisher} source to combine values from * @param source3 The third {@link Publisher} source to combine values from * @param source4 The fourth {@link Publisher} source to combine values from * @param source5 The fifth {@link Publisher} source to combine values from * @param combinator The aggregate function that will receive the latest value from each upstream and return the value * to signal downstream * @param type of the value from source1 * @param type of the value from source2 * @param type of the value from source3 * @param type of the value from source4 * @param type of the value from source5 * @param The produced output after transformation by the given combinator * * @return a {@link Flux} based on the produced combinations */ public static Flux combineLatest(Publisher source1, Publisher source2, Publisher source3, Publisher source4, Publisher source5, Function combinator) { return combineLatest(combinator, source1, source2, source3, source4, source5); } /** * Build a {@link Flux} whose data are generated by the combination of the most recently published value from each * of six {@link Publisher} sources. *

* * * @param source1 The first {@link Publisher} source to combine values from * @param source2 The second {@link Publisher} source to combine values from * @param source3 The third {@link Publisher} source to combine values from * @param source4 The fourth {@link Publisher} source to combine values from * @param source5 The fifth {@link Publisher} source to combine values from * @param source6 The sixth {@link Publisher} source to combine values from * @param combinator The aggregate function that will receive the latest value from each upstream and return the value * to signal downstream * @param type of the value from source1 * @param type of the value from source2 * @param type of the value from source3 * @param type of the value from source4 * @param type of the value from source5 * @param type of the value from source6 * @param The produced output after transformation by the given combinator * * @return a {@link Flux} based on the produced combinations */ public static Flux combineLatest(Publisher source1, Publisher source2, Publisher source3, Publisher source4, Publisher source5, Publisher source6, Function combinator) { return combineLatest(combinator, source1, source2, source3, source4, source5, source6); } /** * Build a {@link Flux} whose data are generated by the combination of the most recently published value from each * of the {@link Publisher} sources provided in an {@link Iterable}. *

* * * @param sources The list of {@link Publisher} sources to combine values from * @param combinator The aggregate function that will receive the latest value from each upstream and return the value * to signal downstream * @param The common base type of the values from sources * @param The produced output after transformation by the given combinator * * @return a {@link Flux} based on the produced combinations */ public static Flux combineLatest(Iterable> sources, Function combinator) { return combineLatest(sources, Queues.XS_BUFFER_SIZE, combinator); } /** * Build a {@link Flux} whose data are generated by the combination of the most recently published value from each * of the {@link Publisher} sources provided in an {@link Iterable}. *

* * * @param sources The list of {@link Publisher} sources to combine values from * @param prefetch demand produced to each combined source {@link Publisher} * @param combinator The aggregate function that will receive the latest value from each upstream and return the value * to signal downstream * @param The common base type of the values from sources * @param The produced output after transformation by the given combinator * * @return a {@link Flux} based on the produced combinations */ public static Flux combineLatest(Iterable> sources, int prefetch, Function combinator) { return onAssembly(new FluxCombineLatest(sources, combinator, Queues.get(prefetch), prefetch)); } /** * Concatenate all sources provided in an {@link Iterable}, forwarding elements * emitted by the sources downstream. *

* Concatenation is achieved by sequentially subscribing to the first source then * waiting for it to complete before subscribing to the next, and so on until the * last source completes. Any error interrupts the sequence immediately and is * forwarded downstream. *

* * * @param sources The {@link Iterable} of {@link Publisher} to concatenate * @param The type of values in both source and output sequences * * @return a new {@link Flux} concatenating all source sequences */ public static Flux concat(Iterable> sources) { return onAssembly(new FluxConcatIterable<>(sources)); } /** * Concatenate all sources emitted as an onNext signal from a parent {@link Publisher}, * forwarding elements emitted by the sources downstream. *

* Concatenation is achieved by sequentially subscribing to the first source then * waiting for it to complete before subscribing to the next, and so on until the * last source completes. Any error interrupts the sequence immediately and is * forwarded downstream. *

* *

* @param sources The {@link Publisher} of {@link Publisher} to concatenate * @param The type of values in both source and output sequences * * @return a new {@link Flux} concatenating all inner sources sequences */ public static Flux concat(Publisher> sources) { return concat(sources, Queues.XS_BUFFER_SIZE); } /** * Concatenate all sources emitted as an onNext signal from a parent {@link Publisher}, * forwarding elements emitted by the sources downstream. *

* Concatenation is achieved by sequentially subscribing to the first source then * waiting for it to complete before subscribing to the next, and so on until the * last source completes. Any error interrupts the sequence immediately and is * forwarded downstream. *

* *

* @param sources The {@link Publisher} of {@link Publisher} to concatenate * @param prefetch the inner source request size * @param The type of values in both source and output sequences * * @return a new {@link Flux} concatenating all inner sources sequences */ public static Flux concat(Publisher> sources, int prefetch) { return onAssembly(new FluxConcatMap<>(from(sources), identityFunction(), Queues.get(prefetch), prefetch, FluxConcatMap.ErrorMode.IMMEDIATE)); } /** * Concatenate all sources provided as a vararg, forwarding elements emitted by the * sources downstream. *

* Concatenation is achieved by sequentially subscribing to the first source then * waiting for it to complete before subscribing to the next, and so on until the * last source completes. Any error interrupts the sequence immediately and is * forwarded downstream. *

* *

* @param sources The {@link Publisher} of {@link Publisher} to concat * @param The type of values in both source and output sequences * * @return a new {@link Flux} concatenating all source sequences */ @SafeVarargs public static Flux concat(Publisher... sources) { return onAssembly(new FluxConcatArray<>(false, sources)); } /** * Concatenate all sources emitted as an onNext signal from a parent {@link Publisher}, * forwarding elements emitted by the sources downstream. *

* Concatenation is achieved by sequentially subscribing to the first source then * waiting for it to complete before subscribing to the next, and so on until the * last source completes. Errors do not interrupt the main sequence but are propagated * after the rest of the sources have had a chance to be concatenated. *

* *

* @param sources The {@link Publisher} of {@link Publisher} to concatenate * @param The type of values in both source and output sequences * * @return a new {@link Flux} concatenating all inner sources sequences, delaying errors */ public static Flux concatDelayError(Publisher> sources) { return concatDelayError(sources, Queues.XS_BUFFER_SIZE); } /** * Concatenate all sources emitted as an onNext signal from a parent {@link Publisher}, * forwarding elements emitted by the sources downstream. *

* Concatenation is achieved by sequentially subscribing to the first source then * waiting for it to complete before subscribing to the next, and so on until the * last source completes. Errors do not interrupt the main sequence but are propagated * after the rest of the sources have had a chance to be concatenated. *

* *

* @param sources The {@link Publisher} of {@link Publisher} to concatenate * @param prefetch the inner source request size * @param The type of values in both source and output sequences * * @return a new {@link Flux} concatenating all inner sources sequences until complete or error */ public static Flux concatDelayError(Publisher> sources, int prefetch) { return onAssembly(new FluxConcatMap<>(from(sources), identityFunction(), Queues.get(prefetch), prefetch, FluxConcatMap.ErrorMode.END)); } /** * Concatenate all sources emitted as an onNext signal from a parent {@link Publisher}, * forwarding elements emitted by the sources downstream. *

* Concatenation is achieved by sequentially subscribing to the first source then * waiting for it to complete before subscribing to the next, and so on until the * last source completes. *

* Errors do not interrupt the main sequence but are propagated after the current * concat backlog if {@code delayUntilEnd} is {@literal false} or after all sources * have had a chance to be concatenated if {@code delayUntilEnd} is {@literal true}. *

* *

* @param sources The {@link Publisher} of {@link Publisher} to concatenate * @param delayUntilEnd delay error until all sources have been consumed instead of * after the current source * @param prefetch the inner source request size * @param The type of values in both source and output sequences * * @return a new {@link Flux} concatenating all inner sources sequences until complete or error */ public static Flux concatDelayError(Publisher> sources, boolean delayUntilEnd, int prefetch) { return onAssembly(new FluxConcatMap<>(from(sources), identityFunction(), Queues.get(prefetch), prefetch, delayUntilEnd ? FluxConcatMap.ErrorMode.END : FluxConcatMap.ErrorMode.BOUNDARY)); } /** * Concatenate all sources provided as a vararg, forwarding elements emitted by the * sources downstream. *

* Concatenation is achieved by sequentially subscribing to the first source then * waiting for it to complete before subscribing to the next, and so on until the * last source completes. Errors do not interrupt the main sequence but are propagated * after the rest of the sources have had a chance to be concatenated. *

* *

* @param sources The {@link Publisher} of {@link Publisher} to concat * @param The type of values in both source and output sequences * * @return a new {@link Flux} concatenating all source sequences */ @SafeVarargs public static Flux concatDelayError(Publisher... sources) { return onAssembly(new FluxConcatArray<>(true, sources)); } /** * Programmatically create a {@link Flux} with the capability of emitting multiple * elements in a synchronous or asynchronous manner through the {@link FluxSink} API. *

* This Flux factory is useful if one wants to adapt some other multi-valued async API * and not worry about cancellation and backpressure (which is handled by buffering * all signals if the downstream can't keep up). *

* For example: * *


	 * Flux.<String>create(emitter -> {
	 *
	 *     ActionListener al = e -> {
	 *         emitter.next(textField.getText());
	 *     };
	 *     // without cleanup support:
	 *
	 *     button.addActionListener(al);
	 *
	 *     // with cleanup support:
	 *
	 *     button.addActionListener(al);
	 *     emitter.onDispose(() -> {
	 *         button.removeListener(al);
	 *     });
	 * });
	 * 
* * @param The type of values in the sequence * @param emitter Consume the {@link FluxSink} provided per-subscriber by Reactor to generate signals. * @return a {@link Flux} */ public static Flux create(Consumer> emitter) { return create(emitter, OverflowStrategy.BUFFER); } /** * Programmatically create a {@link Flux} with the capability of emitting multiple * elements in a synchronous or asynchronous manner through the {@link FluxSink} API. *

* This Flux factory is useful if one wants to adapt some other multi-valued async API * and not worry about cancellation and backpressure (which is handled by buffering * all signals if the downstream can't keep up). *

* For example: * *


     * Flux.<String>create(emitter -> {
     *
     *     ActionListener al = e -> {
     *         emitter.next(textField.getText());
     *     };
     *     // without cleanup support:
     *
     *     button.addActionListener(al);
     *
     *     // with cleanup support:
     *
     *     button.addActionListener(al);
     *     emitter.onDispose(() -> {
     *         button.removeListener(al);
     *     });
     * }, FluxSink.OverflowStrategy.LATEST);
     * 
* * @param The type of values in the sequence * @param backpressure the backpressure mode, see {@link OverflowStrategy} for the * available backpressure modes * @param emitter Consume the {@link FluxSink} provided per-subscriber by Reactor to generate signals. * @return a {@link Flux} */ public static Flux create(Consumer> emitter, OverflowStrategy backpressure) { return onAssembly(new FluxCreate<>(emitter, backpressure, FluxCreate.CreateMode.PUSH_PULL)); } /** * Programmatically create a {@link Flux} with the capability of emitting multiple * elements from a single-threaded producer through the {@link FluxSink} API. *

* This Flux factory is useful if one wants to adapt some other single-threaded * multi-valued async API and not worry about cancellation and backpressure (which is * handled by buffering all signals if the downstream can't keep up). *

* For example: * *


	 * Flux.<String>push(emitter -> {
	 *
	 *	 ActionListener al = e -> {
	 *		 emitter.next(textField.getText());
	 *	 };
	 *	 // without cleanup support:
	 *
	 *	 button.addActionListener(al);
	 *
	 *	 // with cleanup support:
	 *
	 *	 button.addActionListener(al);
	 *	 emitter.onDispose(() -> {
	 *		 button.removeListener(al);
	 *	 });
	 * }, FluxSink.OverflowStrategy.LATEST);
	 * 
* * @param The type of values in the sequence * @param emitter Consume the {@link FluxSink} provided per-subscriber by Reactor to generate signals. * @return a {@link Flux} */ public static Flux push(Consumer> emitter) { return onAssembly(new FluxCreate<>(emitter, OverflowStrategy.BUFFER, FluxCreate.CreateMode.PUSH_ONLY)); } /** * Programmatically create a {@link Flux} with the capability of emitting multiple * elements from a single-threaded producer through the {@link FluxSink} API. *

* This Flux factory is useful if one wants to adapt some other single-threaded * multi-valued async API and not worry about cancellation and backpressure (which is * handled by buffering all signals if the downstream can't keep up). *

* For example: * *


	 * Flux.<String>push(emitter -> {
	 *
	 *	 ActionListener al = e -> {
	 *		 emitter.next(textField.getText());
	 *	 };
	 *	 // without cleanup support:
	 *
	 *	 button.addActionListener(al);
	 *
	 *	 // with cleanup support:
	 *
	 *	 button.addActionListener(al);
	 *	 emitter.onDispose(() -> {
	 *		 button.removeListener(al);
	 *	 });
	 * }, FluxSink.OverflowStrategy.LATEST);
	 * 
* * @param The type of values in the sequence * @param backpressure the backpressure mode, see {@link OverflowStrategy} for the * available backpressure modes * @param emitter Consume the {@link FluxSink} provided per-subscriber by Reactor to generate signals. * @return a {@link Flux} */ public static Flux push(Consumer> emitter, OverflowStrategy backpressure) { return onAssembly(new FluxCreate<>(emitter, backpressure, FluxCreate.CreateMode.PUSH_ONLY)); } /** * Lazily supply a {@link Publisher} every time a {@link Subscription} is made on the * resulting {@link Flux}, so the actual source instantiation is deferred until each * subscribe and the {@link Supplier} can create a subscriber-specific instance. * If the supplier doesn't generate a new instance however, this operator will * effectively behave like {@link #from(Publisher)}. * *

* * * @param supplier the {@link Publisher} {@link Supplier} to call on subscribe * @param the type of values passing through the {@link Flux} * * @return a deferred {@link Flux} */ public static Flux defer(Supplier> supplier) { return onAssembly(new FluxDefer<>(supplier)); } /** * Create a {@link Flux} that completes without emitting any item. *

* *

* @param the reified type of the target {@link Subscriber} * * @return an empty {@link Flux} */ public static Flux empty() { return FluxEmpty.instance(); } /** * Create a {@link Flux} that terminates with the specified error immediately after * being subscribed to. *

* *

* @param error the error to signal to each {@link Subscriber} * @param the reified type of the target {@link Subscriber} * * @return a new failed {@link Flux} */ public static Flux error(Throwable error) { return error(error, false); } /** * Create a {@link Flux} that terminates with the specified error, either immediately * after being subscribed to or after being first requested. * *

* * * @param throwable the error to signal to each {@link Subscriber} * @param whenRequested if true, will onError on the first request instead of subscribe(). * @param the reified type of the target {@link Subscriber} * * @return a new failed {@link Flux} */ public static Flux error(Throwable throwable, boolean whenRequested) { if (whenRequested) { return onAssembly(new FluxErrorOnRequest<>(throwable)); } else { return onAssembly(new FluxError<>(throwable)); } } /** * Pick the first {@link Publisher} to emit any signal (onNext/onError/onComplete) and * replay all signals from that {@link Publisher}, effectively behaving like the * fastest of these competing sources. * *

* *

* * @param sources The competing source publishers * @param The type of values in both source and output sequences * * @return a new {@link Flux} behaving like the fastest of its sources */ @SafeVarargs public static Flux first(Publisher... sources) { return onAssembly(new FluxFirstEmitting<>(sources)); } /** * Pick the first {@link Publisher} to emit any signal (onNext/onError/onComplete) and * replay all signals from that {@link Publisher}, effectively behaving like the * fastest of these competing sources. * *

* *

* * @param sources The competing source publishers * @param The type of values in both source and output sequences * * @return a new {@link Flux} behaving like the fastest of its sources */ public static Flux first(Iterable> sources) { return onAssembly(new FluxFirstEmitting<>(sources)); } /** * Decorate the specified {@link Publisher} with the {@link Flux} API. *

* *

* @param source the source to decorate * @param The type of values in both source and output sequences * * @return a new {@link Flux} */ public static Flux from(Publisher source) { if (source instanceof Flux) { @SuppressWarnings("unchecked") Flux casted = (Flux) source; return casted; } if (source instanceof Fuseable.ScalarCallable) { try { @SuppressWarnings("unchecked") T t = ((Fuseable.ScalarCallable) source).call(); if (t != null) { return just(t); } return empty(); } catch (Exception e) { return error(e); } } return wrap(source); } /** * Create a {@link Flux} that emits the items contained in the provided array. *

* *

* @param array the array to read data from * @param The type of values in the source array and resulting Flux * * @return a new {@link Flux} */ public static Flux fromArray(T[] array) { if (array.length == 0) { return empty(); } if (array.length == 1) { return just(array[0]); } return onAssembly(new FluxArray<>(array)); } /** * Create a {@link Flux} that emits the items contained in the provided {@link Iterable}. * A new iterator will be created for each subscriber. *

* *

* @param it the {@link Iterable} to read data from * @param The type of values in the source {@link Iterable} and resulting Flux * * @return a new {@link Flux} */ public static Flux fromIterable(Iterable it) { return onAssembly(new FluxIterable<>(it)); } /** * Create a {@link Flux} that emits the items contained in the provided {@link Stream}. * Keep in mind that a {@link Stream} cannot be re-used, which can be problematic in * case of multiple subscriptions or re-subscription (like with {@link #repeat()} or * {@link #retry()}). *

* *

* @param s the {@link Stream} to read data from * @param The type of values in the source {@link Stream} and resulting Flux * * @return a new {@link Flux} */ public static Flux fromStream(Stream s) { return onAssembly(new FluxStream<>(s)); } /** * Programmatically create a {@link Flux} by generating signals one-by-one via a * consumer callback. *

* *

* * @param the value type emitted * @param generator Consume the {@link SynchronousSink} provided per-subscriber by Reactor * to generate a single signal on each pass. * * @return a {@link Flux} */ public static Flux generate(Consumer> generator) { Objects.requireNonNull(generator, "generator"); return onAssembly(new FluxGenerate<>(generator)); } /** * Programmatically create a {@link Flux} by generating signals one-by-one via a * consumer callback and some state. The {@code stateSupplier} may return {@literal null}. *

* *

* * @param the value type emitted * @param the per-subscriber custom state type * @param stateSupplier called for each incoming Subscriber to provide the initial state for the generator bifunction * @param generator Consume the {@link SynchronousSink} provided per-subscriber by Reactor * as well as the current state to generate a single signal on each pass * and return a (new) state. * @return a {@link Flux} */ public static Flux generate(Callable stateSupplier, BiFunction, S> generator) { return onAssembly(new FluxGenerate<>(stateSupplier, generator)); } /** * Programmatically create a {@link Flux} by generating signals one-by-one via a * consumer callback and some state, with a final cleanup callback. The * {@code stateSupplier} may return {@literal null} but your cleanup {@code stateConsumer} * will need to handle the null case. *

* *

* * @param the value type emitted * @param the per-subscriber custom state type * @param stateSupplier called for each incoming Subscriber to provide the initial state for the generator bifunction * @param generator Consume the {@link SynchronousSink} provided per-subscriber by Reactor * as well as the current state to generate a single signal on each pass * and return a (new) state. * @param stateConsumer called after the generator has terminated or the downstream cancelled, receiving the last * state to be handled (i.e., release resources or do other cleanup). * * @return a {@link Flux} */ public static Flux generate(Callable stateSupplier, BiFunction, S> generator, Consumer stateConsumer) { return onAssembly(new FluxGenerate<>(stateSupplier, generator, stateConsumer)); } /** * Create a {@link Flux} that emits long values starting with 0 and incrementing at * specified time intervals on the global timer. If demand is not produced in time, * an onError will be signalled with an {@link Exceptions#isOverflow(Throwable) overflow} * {@code IllegalStateException} detailing the tick that couldn't be emitted. * In normal conditions, the {@link Flux} will never complete. *

* Runs on the {@link Schedulers#parallel()} Scheduler. *

* *

* @param period the period {@link Duration} between each increment * @return a new {@link Flux} emitting increasing numbers at regular intervals */ public static Flux interval(Duration period) { return interval(period, Schedulers.parallel()); } /** * Create a {@link Flux} that emits long values starting with 0 and incrementing at * specified time intervals, after an initial delay, on the global timer. If demand is * not produced in time, an onError will be signalled with an * {@link Exceptions#isOverflow(Throwable) overflow} {@code IllegalStateException} * detailing the tick that couldn't be emitted. In normal conditions, the {@link Flux} * will never complete. *

* Runs on the {@link Schedulers#parallel()} Scheduler. *

* * * @param delay the {@link Duration} to wait before emitting 0l * @param period the period {@link Duration} before each following increment * * @return a new {@link Flux} emitting increasing numbers at regular intervals */ public static Flux interval(Duration delay, Duration period) { return interval(delay, period, Schedulers.parallel()); } /** * Create a {@link Flux} that emits long values starting with 0 and incrementing at * specified time intervals, on the specified {@link Scheduler}. If demand is not * produced in time, an onError will be signalled with an {@link Exceptions#isOverflow(Throwable) overflow} * {@code IllegalStateException} detailing the tick that couldn't be emitted. * In normal conditions, the {@link Flux} will never complete. *

* *

* @param period the period {@link Duration} between each increment * @param timer a time-capable {@link Scheduler} instance to run on * * @return a new {@link Flux} emitting increasing numbers at regular intervals */ public static Flux interval(Duration period, Scheduler timer) { return onAssembly(new FluxInterval(period.toMillis(), period.toMillis(), TimeUnit.MILLISECONDS, timer)); } /** * Create a {@link Flux} that emits long values starting with 0 and incrementing at * specified time intervals, after an initial delay, on the specified {@link Scheduler}. * If demand is not produced in time, an onError will be signalled with an * {@link Exceptions#isOverflow(Throwable) overflow} {@code IllegalStateException} * detailing the tick that couldn't be emitted. In normal conditions, the {@link Flux} * will never complete. *

* * * @param delay the {@link Duration} to wait before emitting 0l * @param period the period {@link Duration} before each following increment * @param timer a time-capable {@link Scheduler} instance to run on * * @return a new {@link Flux} emitting increasing numbers at regular intervals */ public static Flux interval(Duration delay, Duration period, Scheduler timer) { return onAssembly(new FluxInterval(delay.toMillis(), period.toMillis(), TimeUnit.MILLISECONDS, timer)); } /** * Create a {@link Flux} that emits the provided elements and then completes. *

* *

* @param data the elements to emit, as a vararg * @param the emitted data type * * @return a new {@link Flux} */ @SafeVarargs public static Flux just(T... data) { return fromArray(data); } /** * Create a new {@link Flux} that will only emit a single element then onComplete. *

* *

* @param data the single element to emit * @param the emitted data type * * @return a new {@link Flux} */ public static Flux just(T data) { return onAssembly(new FluxJust<>(data)); } /** * Merge data from {@link Publisher} sequences emitted by the passed {@link Publisher} * into an interleaved merged sequence. Unlike {@link #concat(Publisher) concat}, inner * sources are subscribed to eagerly. *

* *

* Note that merge is tailored to work with asynchronous sources or finite sources. When dealing with * an infinite source that doesn't already publish on a dedicated Scheduler, you must isolate that source * in its own Scheduler, as merge would otherwise attempt to drain it before subscribing to * another source. * * @param source a {@link Publisher} of {@link Publisher} sources to merge * @param the merged type * * @return a merged {@link Flux} */ public static Flux merge(Publisher> source) { return merge(source, Queues.SMALL_BUFFER_SIZE, Queues.XS_BUFFER_SIZE); } /** * Merge data from {@link Publisher} sequences emitted by the passed {@link Publisher} * into an interleaved merged sequence. Unlike {@link #concat(Publisher) concat}, inner * sources are subscribed to eagerly (but at most {@code concurrency} sources are * subscribed to at the same time). *

* *

* Note that merge is tailored to work with asynchronous sources or finite sources. When dealing with * an infinite source that doesn't already publish on a dedicated Scheduler, you must isolate that source * in its own Scheduler, as merge would otherwise attempt to drain it before subscribing to * another source. * * @param source a {@link Publisher} of {@link Publisher} sources to merge * @param concurrency the request produced to the main source thus limiting concurrent merge backlog * @param the merged type * * @return a merged {@link Flux} */ public static Flux merge(Publisher> source, int concurrency) { return merge(source, concurrency, Queues.XS_BUFFER_SIZE); } /** * Merge data from {@link Publisher} sequences emitted by the passed {@link Publisher} * into an interleaved merged sequence. Unlike {@link #concat(Publisher) concat}, inner * sources are subscribed to eagerly (but at most {@code concurrency} sources are * subscribed to at the same time). *

* *

* Note that merge is tailored to work with asynchronous sources or finite sources. When dealing with * an infinite source that doesn't already publish on a dedicated Scheduler, you must isolate that source * in its own Scheduler, as merge would otherwise attempt to drain it before subscribing to * another source. * * @param source a {@link Publisher} of {@link Publisher} sources to merge * @param concurrency the request produced to the main source thus limiting concurrent merge backlog * @param prefetch the inner source request size * @param the merged type * * @return a merged {@link Flux} */ public static Flux merge(Publisher> source, int concurrency, int prefetch) { return onAssembly(new FluxFlatMap<>( from(source), identityFunction(), false, concurrency, Queues.get(concurrency), prefetch, Queues.get(prefetch))); } /** * Merge data from {@link Publisher} sequences contained in an {@link Iterable} * into an interleaved merged sequence. Unlike {@link #concat(Publisher) concat}, inner * sources are subscribed to eagerly. * A new {@link Iterator} will be created for each subscriber. *

* *

* Note that merge is tailored to work with asynchronous sources or finite sources. When dealing with * an infinite source that doesn't already publish on a dedicated Scheduler, you must isolate that source * in its own Scheduler, as merge would otherwise attempt to drain it before subscribing to * another source. * * @param sources the {@link Iterable} of sources to merge (will be lazily iterated on subscribe) * @param The source type of the data sequence * * @return a merged {@link Flux} */ public static Flux merge(Iterable> sources) { return merge(fromIterable(sources)); } /** * Merge data from {@link Publisher} sequences contained in an array / vararg * into an interleaved merged sequence. Unlike {@link #concat(Publisher) concat}, inner * sources are subscribed to eagerly. *

* *

* Note that merge is tailored to work with asynchronous sources or finite sources. When dealing with * an infinite source that doesn't already publish on a dedicated Scheduler, you must isolate that source * in its own Scheduler, as merge would otherwise attempt to drain it before subscribing to * another source. * * @param sources the array of {@link Publisher} sources to merge * @param The source type of the data sequence * * @return a merged {@link Flux} */ @SafeVarargs public static Flux merge(Publisher... sources) { return merge(Queues.XS_BUFFER_SIZE, sources); } /** * Merge data from {@link Publisher} sequences contained in an array / vararg * into an interleaved merged sequence. Unlike {@link #concat(Publisher) concat}, inner * sources are subscribed to eagerly. *

* *

* Note that merge is tailored to work with asynchronous sources or finite sources. When dealing with * an infinite source that doesn't already publish on a dedicated Scheduler, you must isolate that source * in its own Scheduler, as merge would otherwise attempt to drain it before subscribing to * another source. * * @param sources the array of {@link Publisher} sources to merge * @param prefetch the inner source request size * @param The source type of the data sequence * * @return a fresh Reactive {@link Flux} publisher ready to be subscribed */ @SafeVarargs public static Flux merge(int prefetch, Publisher... sources) { return merge(prefetch, false, sources); } /** * Merge data from {@link Publisher} sequences contained in an array / vararg * into an interleaved merged sequence. Unlike {@link #concat(Publisher) concat}, inner * sources are subscribed to eagerly. * This variant will delay any error until after the rest of the merge backlog has been processed. *

* *

* Note that merge is tailored to work with asynchronous sources or finite sources. When dealing with * an infinite source that doesn't already publish on a dedicated Scheduler, you must isolate that source * in its own Scheduler, as merge would otherwise attempt to drain it before subscribing to * another source. * * @param sources the array of {@link Publisher} sources to merge * @param prefetch the inner source request size * @param The source type of the data sequence * * @return a fresh Reactive {@link Flux} publisher ready to be subscribed */ @SafeVarargs public static Flux mergeDelayError(int prefetch, Publisher... sources) { return merge(prefetch, true, sources); } /** * Merge data from {@link Publisher} sequences emitted by the passed {@link Publisher} * into an ordered merged sequence. Unlike concat, the inner publishers are subscribed to * eagerly. Unlike merge, their emitted values are merged into the final sequence in * subscription order. *

* *

* @param sources a {@link Publisher} of {@link Publisher} sources to merge * @param the merged type * * @return a merged {@link Flux}, subscribing early but keeping the original ordering */ public static Flux mergeSequential(Publisher> sources) { return mergeSequential(sources, false, Queues.SMALL_BUFFER_SIZE, Queues.XS_BUFFER_SIZE); } /** * Merge data from {@link Publisher} sequences emitted by the passed {@link Publisher} * into an ordered merged sequence. Unlike concat, the inner publishers are subscribed to * eagerly (but at most {@code maxConcurrency} sources at a time). Unlike merge, their * emitted values are merged into the final sequence in subscription order. *

* *

* @param sources a {@link Publisher} of {@link Publisher} sources to merge * @param prefetch the inner source request size * @param maxConcurrency the request produced to the main source thus limiting concurrent merge backlog * @param the merged type * * @return a merged {@link Flux}, subscribing early but keeping the original ordering */ public static Flux mergeSequential(Publisher> sources, int maxConcurrency, int prefetch) { return mergeSequential(sources, false, maxConcurrency, prefetch); } /** * Merge data from {@link Publisher} sequences emitted by the passed {@link Publisher} * into an ordered merged sequence. Unlike concat, the inner publishers are subscribed to * eagerly (but at most {@code maxConcurrency} sources at a time). Unlike merge, their * emitted values are merged into the final sequence in subscription order. * This variant will delay any error until after the rest of the mergeSequential backlog has been processed. *

* *

* @param sources a {@link Publisher} of {@link Publisher} sources to merge * @param prefetch the inner source request size * @param maxConcurrency the request produced to the main source thus limiting concurrent merge backlog * @param the merged type * * @return a merged {@link Flux}, subscribing early but keeping the original ordering */ public static Flux mergeSequentialDelayError(Publisher> sources, int maxConcurrency, int prefetch) { return mergeSequential(sources, true, maxConcurrency, prefetch); } /** * Merge data from {@link Publisher} sequences provided in an array/vararg * into an ordered merged sequence. Unlike concat, the inner publishers are subscribed to * eagerly. Unlike merge, their emitted values are merged into the final sequence in subscription order. *

* *

* @param sources a number of {@link Publisher} sequences to merge * @param the merged type * * @return a merged {@link Flux}, subscribing early but keeping the original ordering */ @SafeVarargs public static Flux mergeSequential(Publisher... sources) { return mergeSequential(Queues.XS_BUFFER_SIZE, false, sources); } /** * Merge data from {@link Publisher} sequences provided in an array/vararg * into an ordered merged sequence. Unlike concat, the inner publishers are subscribed to * eagerly. Unlike merge, their emitted values are merged into the final sequence in subscription order. *

* *

* @param prefetch the inner source request size * @param sources a number of {@link Publisher} sequences to merge * @param the merged type * * @return a merged {@link Flux}, subscribing early but keeping the original ordering */ @SafeVarargs public static Flux mergeSequential(int prefetch, Publisher... sources) { return mergeSequential(prefetch, false, sources); } /** * Merge data from {@link Publisher} sequences provided in an array/vararg * into an ordered merged sequence. Unlike concat, the inner publishers are subscribed to * eagerly. Unlike merge, their emitted values are merged into the final sequence in subscription order. * This variant will delay any error until after the rest of the mergeSequential backlog * has been processed. *

* *

* @param prefetch the inner source request size * @param sources a number of {@link Publisher} sequences to merge * @param the merged type * * @return a merged {@link Flux}, subscribing early but keeping the original ordering */ @SafeVarargs public static Flux mergeSequentialDelayError(int prefetch, Publisher... sources) { return mergeSequential(prefetch, true, sources); } /** * Merge data from {@link Publisher} sequences provided in an {@link Iterable} * into an ordered merged sequence. Unlike concat, the inner publishers are subscribed to * eagerly. Unlike merge, their emitted values are merged into the final sequence in subscription order. *

* *

* @param sources an {@link Iterable} of {@link Publisher} sequences to merge * @param the merged type * * @return a merged {@link Flux}, subscribing early but keeping the original ordering */ public static Flux mergeSequential(Iterable> sources) { return mergeSequential(sources, false, Queues.SMALL_BUFFER_SIZE, Queues.XS_BUFFER_SIZE); } /** * Merge data from {@link Publisher} sequences provided in an {@link Iterable} * into an ordered merged sequence. Unlike concat, the inner publishers are subscribed to * eagerly (but at most {@code maxConcurrency} sources at a time). Unlike merge, their * emitted values are merged into the final sequence in subscription order. *

* *

* @param sources an {@link Iterable} of {@link Publisher} sequences to merge * @param maxConcurrency the request produced to the main source thus limiting concurrent merge backlog * @param prefetch the inner source request size * @param the merged type * * @return a merged {@link Flux}, subscribing early but keeping the original ordering */ public static Flux mergeSequential(Iterable> sources, int maxConcurrency, int prefetch) { return mergeSequential(sources, false, maxConcurrency, prefetch); } /** * Merge data from {@link Publisher} sequences provided in an {@link Iterable} * into an ordered merged sequence. Unlike concat, the inner publishers are subscribed to * eagerly (but at most {@code maxConcurrency} sources at a time). Unlike merge, their * emitted values are merged into the final sequence in subscription order. * This variant will delay any error until after the rest of the mergeSequential backlog * has been processed. *

* *

* @param sources an {@link Iterable} of {@link Publisher} sequences to merge * @param maxConcurrency the request produced to the main source thus limiting concurrent merge backlog * @param prefetch the inner source request size * @param the merged type * * @return a merged {@link Flux}, subscribing early but keeping the original ordering */ public static Flux mergeSequentialDelayError(Iterable> sources, int maxConcurrency, int prefetch) { return mergeSequential(sources, true, maxConcurrency, prefetch); } /** * Create a {@link Flux} that will never signal any data, error or completion signal. *

* *

* @param the {@link Subscriber} type target * * @return a never completing {@link Flux} */ public static Flux never() { return FluxNever.instance(); } /** * Build a {@link Flux} that will only emit a sequence of {@code count} incrementing integers, * starting from {@code start}. That is, emit integers between {@code start} (included) * and {@code start + count} (excluded) then complete. * *

* * * @param start the first integer to be emit * @param count the total number of incrementing values to emit, including the first value * @return a ranged {@link Flux} */ public static Flux range(int start, int count) { if (count == 1) { return just(start); } if (count == 0) { return empty(); } return onAssembly(new FluxRange(start, count)); } /** * Creates a {@link Flux} that mirrors the most recently emitted {@link Publisher}, * forwarding its data until a new {@link Publisher} comes in in the source. *

* The resulting {@link Flux} will complete once there are no new {@link Publisher} in * the source (source has completed) and the last mirrored {@link Publisher} has also * completed. *

* * * @param mergedPublishers The {@link Publisher} of {@link Publisher} to switch on and mirror. * @param the produced type * * @return a {@link FluxProcessor} accepting publishers and producing T */ public static Flux switchOnNext(Publisher> mergedPublishers) { return switchOnNext(mergedPublishers, Queues.XS_BUFFER_SIZE); } /** * Creates a {@link Flux} that mirrors the most recently emitted {@link Publisher}, * forwarding its data until a new {@link Publisher} comes in in the source. *

* The resulting {@link Flux} will complete once there are no new {@link Publisher} in * the source (source has completed) and the last mirrored {@link Publisher} has also * completed. *

* * * @param mergedPublishers The {@link Publisher} of {@link Publisher} to switch on and mirror. * @param prefetch the inner source request size * @param the produced type * * @return a {@link FluxProcessor} accepting publishers and producing T */ public static Flux switchOnNext(Publisher> mergedPublishers, int prefetch) { return onAssembly(new FluxSwitchMap<>(from(mergedPublishers), identityFunction(), Queues.unbounded(prefetch), prefetch)); } /** * Uses a resource, generated by a supplier for each individual Subscriber, while streaming the values from a * Publisher derived from the same resource and makes sure the resource is released if the sequence terminates or * the Subscriber cancels. *

* Eager resource cleanup happens just before the source termination and exceptions raised by the cleanup Consumer * may override the terminal even. *

* * * @param resourceSupplier a {@link Callable} that is called on subscribe to generate the resource * @param sourceSupplier a factory to derive a {@link Publisher} from the supplied resource * @param resourceCleanup a resource cleanup callback invoked on completion * @param emitted type * @param resource type * * @return a new {@link Flux} built around a disposable resource */ public static Flux using(Callable resourceSupplier, Function> sourceSupplier, Consumer resourceCleanup) { return using(resourceSupplier, sourceSupplier, resourceCleanup, true); } /** * Uses a resource, generated by a supplier for each individual Subscriber, while streaming the values from a * Publisher derived from the same resource and makes sure the resource is released if the sequence terminates or * the Subscriber cancels. *

*

  • Eager resource cleanup happens just before the source termination and exceptions raised by the cleanup * Consumer may override the terminal even.
  • Non-eager cleanup will drop any exception.
*

* * * @param resourceSupplier a {@link Callable} that is called on subscribe to generate the resource * @param sourceSupplier a factory to derive a {@link Publisher} from the supplied resource * @param resourceCleanup a resource cleanup callback invoked on completion * @param eager true to clean before terminating downstream subscribers * @param emitted type * @param resource type * * @return a new {@link Flux} built around a disposable resource */ public static Flux using(Callable resourceSupplier, Function> sourceSupplier, Consumer resourceCleanup, boolean eager) { return onAssembly(new FluxUsing<>(resourceSupplier, sourceSupplier, resourceCleanup, eager)); } /** * Zip two sources together, that is to say wait for all the sources to emit one * element and combine these elements once into an output value (constructed by the provided * combinator). The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. *

* *

* * @param source1 The first {@link Publisher} source to zip. * @param source2 The second {@link Publisher} source to zip. * @param combinator The aggregate function that will receive a unique value from each upstream and return the * value to signal downstream * @param type of the value from source1 * @param type of the value from source2 * @param The produced output after transformation by the combinator * * @return a zipped {@link Flux} */ public static Flux zip(Publisher source1, Publisher source2, final BiFunction combinator) { return onAssembly(new FluxZip(source1, source2, combinator, Queues.xs(), Queues.XS_BUFFER_SIZE)); } /** * Zip two sources together, that is to say wait for all the sources to emit one * element and combine these elements once into a {@link Tuple2}. * The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. *

* *

* @param source1 The first {@link Publisher} source to zip. * @param source2 The second {@link Publisher} source to zip. * @param type of the value from source1 * @param type of the value from source2 * * @return a zipped {@link Flux} */ public static Flux> zip(Publisher source1, Publisher source2) { return zip(source1, source2, tuple2Function()); } /** * Zip three sources together, that is to say wait for all the sources to emit one * element and combine these elements once into a {@link Tuple3}. * The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. *

* *

* @param source1 The first upstream {@link Publisher} to subscribe to. * @param source2 The second upstream {@link Publisher} to subscribe to. * @param source3 The third upstream {@link Publisher} to subscribe to. * @param type of the value from source1 * @param type of the value from source2 * @param type of the value from source3 * * @return a zipped {@link Flux} */ public static Flux> zip(Publisher source1, Publisher source2, Publisher source3) { return zip(Tuples.fn3(), source1, source2, source3); } /** * Zip four sources together, that is to say wait for all the sources to emit one * element and combine these elements once into a {@link Tuple4}. * The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. *

* *

* @param source1 The first upstream {@link Publisher} to subscribe to. * @param source2 The second upstream {@link Publisher} to subscribe to. * @param source3 The third upstream {@link Publisher} to subscribe to. * @param source4 The fourth upstream {@link Publisher} to subscribe to. * @param type of the value from source1 * @param type of the value from source2 * @param type of the value from source3 * @param type of the value from source4 * * @return a zipped {@link Flux} */ public static Flux> zip(Publisher source1, Publisher source2, Publisher source3, Publisher source4) { return zip(Tuples.fn4(), source1, source2, source3, source4); } /** * Zip five sources together, that is to say wait for all the sources to emit one * element and combine these elements once into a {@link Tuple5}. * The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. *

* *

* @param source1 The first upstream {@link Publisher} to subscribe to. * @param source2 The second upstream {@link Publisher} to subscribe to. * @param source3 The third upstream {@link Publisher} to subscribe to. * @param source4 The fourth upstream {@link Publisher} to subscribe to. * @param source5 The fifth upstream {@link Publisher} to subscribe to. * @param type of the value from source1 * @param type of the value from source2 * @param type of the value from source3 * @param type of the value from source4 * @param type of the value from source5 * * @return a zipped {@link Flux} */ public static Flux> zip(Publisher source1, Publisher source2, Publisher source3, Publisher source4, Publisher source5) { return zip(Tuples.fn5(), source1, source2, source3, source4, source5); } /** * Zip six sources together, that is to say wait for all the sources to emit one * element and combine these elements once into a {@link Tuple6}. * The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. *

* *

* @param source1 The first upstream {@link Publisher} to subscribe to. * @param source2 The second upstream {@link Publisher} to subscribe to. * @param source3 The third upstream {@link Publisher} to subscribe to. * @param source4 The fourth upstream {@link Publisher} to subscribe to. * @param source5 The fifth upstream {@link Publisher} to subscribe to. * @param source6 The sixth upstream {@link Publisher} to subscribe to. * @param type of the value from source1 * @param type of the value from source2 * @param type of the value from source3 * @param type of the value from source4 * @param type of the value from source5 * @param type of the value from source6 * * @return a zipped {@link Flux} */ public static Flux> zip(Publisher source1, Publisher source2, Publisher source3, Publisher source4, Publisher source5, Publisher source6) { return zip(Tuples.fn6(), source1, source2, source3, source4, source5, source6); } /** * Zip multiple sources together, that is to say wait for all the sources to emit one * element and combine these elements once into an output value (constructed by the provided * combinator). * The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. * * The {@link Iterable#iterator()} will be called on each {@link Publisher#subscribe(Subscriber)}. * *

* * * @param sources the {@link Iterable} providing sources to zip * @param combinator The aggregate function that will receive a unique value from each upstream and return the value * to signal downstream * @param the combined produced type * * @return a zipped {@link Flux} */ public static Flux zip(Iterable> sources, final Function combinator) { return zip(sources, Queues.XS_BUFFER_SIZE, combinator); } /** * Zip multiple sources together, that is to say wait for all the sources to emit one * element and combine these elements once into an output value (constructed by the provided * combinator). * The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. * * The {@link Iterable#iterator()} will be called on each {@link Publisher#subscribe(Subscriber)}. * *

* * * @param sources the {@link Iterable} providing sources to zip * @param prefetch the inner source request size * @param combinator The aggregate function that will receive a unique value from each upstream and return the value * to signal downstream * @param the combined produced type * * @return a zipped {@link Flux} */ public static Flux zip(Iterable> sources, int prefetch, final Function combinator) { return onAssembly(new FluxZip(sources, combinator, Queues.get(prefetch), prefetch)); } /** * Zip multiple sources together, that is to say wait for all the sources to emit one * element and combine these elements once into an output value (constructed by the provided * combinator). * The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. *

* *

* @param combinator The aggregate function that will receive a unique value from each upstream and return the * value to signal downstream * @param sources the array providing sources to zip * @param the type of the input sources * @param the combined produced type * * @return a zipped {@link Flux} */ @SafeVarargs public static Flux zip( final Function combinator, Publisher... sources) { return zip(combinator, Queues.XS_BUFFER_SIZE, sources); } /** * Zip multiple sources together, that is to say wait for all the sources to emit one * element and combine these elements once into an output value (constructed by the provided * combinator). * The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. *

* *

* @param combinator The aggregate function that will receive a unique value from each upstream and return the * value to signal downstream * @param prefetch individual source request size * @param sources the array providing sources to zip * @param the type of the input sources * @param the combined produced type * * @return a zipped {@link Flux} */ @SafeVarargs public static Flux zip(final Function combinator, int prefetch, Publisher... sources) { if (sources.length == 0) { return empty(); } if (sources.length == 1) { Publisher source = sources[0]; if (source instanceof Fuseable) { return onAssembly(new FluxMapFuseable<>(from(source), v -> combinator.apply(new Object[]{v}))); } return onAssembly(new FluxMap<>(from(source), v -> combinator.apply(new Object[]{v}))); } return onAssembly(new FluxZip<>(sources, combinator, Queues.get(prefetch), prefetch)); } /** * Zip multiple sources together, that is to say wait for all the sources to emit one * element and combine these elements once into an output value (constructed by the provided * combinator). * The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. *

* Note that the {@link Publisher} sources from the outer {@link Publisher} will * accumulate into an exhaustive list before starting zip operation. *

* * * @param sources The {@link Publisher} of {@link Publisher} sources to zip. A finite publisher is required. * @param combinator The aggregate function that will receive a unique value from each upstream and return the value * to signal downstream * @param the raw tuple type * @param The produced output after transformation by the given combinator * * @return a {@link Flux} based on the produced value */ @SuppressWarnings({ "rawtypes", "unchecked" }) public static Flux zip(Publisher> sources, final Function combinator) { return onAssembly(new FluxBuffer<>(from(sources), Integer.MAX_VALUE, listSupplier()) .flatMap(new Function>, Publisher>() { @Override public Publisher apply(List> publishers) { return zip(Tuples.fnAny((Function) combinator), publishers.toArray(new Publisher[publishers .size()])); } })); } /** * * Emit a single boolean true if all values of this sequence match * the {@link Predicate}. *

* The implementation uses short-circuit logic and completes with false if * the predicate doesn't match a value. * *

* * * @param predicate the {@link Predicate} that needs to apply to all emitted items * * @return a new {@link Mono} with true if all values satisfies a predicate and false * otherwise */ public final Mono all(Predicate predicate) { return Mono.onAssembly(new MonoAll<>(this, predicate)); } /** * Emit a single boolean true if any of the values of this {@link Flux} sequence match * the predicate. *

* The implementation uses short-circuit logic and completes with false if any value * doesn't match the predicate. * *

* * * @param predicate the {@link Predicate} that needs to apply to at least one emitted item * * @return a new {@link Mono} with true if any value satisfies a predicate and false * otherwise */ public final Mono any(Predicate predicate) { return Mono.onAssembly(new MonoAny<>(this, predicate)); } /** * Transform this {@link Flux} into a target type. *

	 * {@code flux.as(Mono::from).subscribe() }
	 * 
* * @param transformer the {@link Function} to immediately map this {@link Flux} * into a target type instance. * @param

the returned instance type * * @return the {@link Flux} transformed to an instance of P * @see #compose for a bounded conversion to {@link Publisher} */ public final

P as(Function, P> transformer) { return transformer.apply(this); } /** * Subscribe to this {@link Flux} and block indefinitely * until the upstream signals its first value or completes. Returns that value, * or null if the Flux completes empty. In case the Flux errors, the original * exception is thrown (wrapped in a {@link RuntimeException} if it was a checked * exception). *

* Note that each blockFirst() will trigger a new subscription: in other words, * the result might miss signal from hot publishers. * * @return the first value or null */ @Nullable public final T blockFirst() { BlockingFirstSubscriber subscriber = new BlockingFirstSubscriber<>(); onLastAssembly(this).subscribe(Operators.toCoreSubscriber(subscriber)); return subscriber.blockingGet(); } /** * Subscribe to this {@link Flux} and block until the upstream * signals its first value, completes or a timeout expires. Returns that value, * or null if the Flux completes empty. In case the Flux errors, the original * exception is thrown (wrapped in a {@link RuntimeException} if it was a checked * exception). If the provided timeout expires,a {@link RuntimeException} is thrown. *

* Note that each blockFirst() will trigger a new subscription: in other words, * the result might miss signal from hot publishers. * * @param timeout maximum time period to wait for before raising a {@link RuntimeException} * @return the first value or null */ @Nullable public final T blockFirst(Duration timeout) { BlockingFirstSubscriber subscriber = new BlockingFirstSubscriber<>(); onLastAssembly(this).subscribe(Operators.toCoreSubscriber(subscriber)); return subscriber.blockingGet(timeout.toMillis(), TimeUnit.MILLISECONDS); } /** * Subscribe to this {@link Flux} and block indefinitely * until the upstream signals its last value or completes. Returns that value, * or null if the Flux completes empty. In case the Flux errors, the original * exception is thrown (wrapped in a {@link RuntimeException} if it was a checked * exception). *

* Note that each blockLast() will trigger a new subscription: in other words, * the result might miss signal from hot publishers. * * @return the first value or null */ @Nullable public final T blockLast() { BlockingLastSubscriber subscriber = new BlockingLastSubscriber<>(); onLastAssembly(this).subscribe(Operators.toCoreSubscriber(subscriber)); return subscriber.blockingGet(); } /** * Subscribe to this {@link Flux} and block until the upstream * signals its last value, completes or a timeout expires. Returns that value, * or null if the Flux completes empty. In case the Flux errors, the original * exception is thrown (wrapped in a {@link RuntimeException} if it was a checked * exception). If the provided timeout expires,a {@link RuntimeException} is thrown. *

* Note that each blockLast() will trigger a new subscription: in other words, * the result might miss signal from hot publishers. * * @param timeout maximum time period to wait for before raising a {@link RuntimeException} * @return the first value or null */ @Nullable public final T blockLast(Duration timeout) { BlockingLastSubscriber subscriber = new BlockingLastSubscriber<>(); onLastAssembly(this).subscribe(Operators.toCoreSubscriber(subscriber)); return subscriber.blockingGet(timeout.toMillis(), TimeUnit.MILLISECONDS); } /** * Collect all incoming values into a single {@link List} buffer that will be emitted * by the returned {@link Flux} once this Flux completes. *

* * * @return a buffered {@link Flux} of at most one {@link List} * @see #collectList() for an alternative collecting algorithm returning {@link Mono} */ public final Flux> buffer() { return buffer(Integer.MAX_VALUE); } /** * Collect incoming values into multiple {@link List} buffers that will be emitted * by the returned {@link Flux} each time the given max size is reached or once this * Flux completes. *

* * * @param maxSize the maximum collected size * * @return a microbatched {@link Flux} of {@link List} */ public final Flux> buffer(int maxSize) { return buffer(maxSize, listSupplier()); } /** * Collect incoming values into multiple user-defined {@link Collection} buffers that * will be emitted by the returned {@link Flux} each time the given max size is reached * or once this Flux completes. *

* * * @param maxSize the maximum collected size * @param bufferSupplier a {@link Supplier} of the concrete {@link Collection} to use for each buffer * @param the {@link Collection} buffer type * * @return a microbatched {@link Flux} of {@link Collection} */ public final > Flux buffer(int maxSize, Supplier bufferSupplier) { return onAssembly(new FluxBuffer<>(this, maxSize, bufferSupplier)); } /** * Collect incoming values into multiple {@link List} buffers that will be emitted * by the returned {@link Flux} each time the given max size is reached or once this * Flux completes. Buffers can be created with gaps, as a new buffer will be created * every time {@code skip} values have been emitted by the source. *

* When maxSize < skip : dropping buffers *

* *

* When maxSize > skip : overlapping buffers *

* *

* When maxSize == skip : exact buffers *

* * * @param skip the number of items to count before creating a new buffer * @param maxSize the max collected size * * @return a microbatched {@link Flux} of possibly overlapped or gapped {@link List} */ public final Flux> buffer(int maxSize, int skip) { return buffer(maxSize, skip, listSupplier()); } /** * Collect incoming values into multiple user-defined {@link Collection} buffers that * will be emitted by the returned {@link Flux} each time the given max size is reached * or once this Flux completes. Buffers can be created with gaps, as a new buffer will * be created every time {@code skip} values have been emitted by the source *

* When maxSize < skip : dropping buffers *

* *

* When maxSize > skip : overlapping buffers *

* *

* When maxSize == skip : exact buffers *

* * * @param skip the number of items to count before creating a new buffer * @param maxSize the max collected size * @param bufferSupplier a {@link Supplier} of the concrete {@link Collection} to use for each buffer * @param the {@link Collection} buffer type * * @return a microbatched {@link Flux} of possibly overlapped or gapped * {@link Collection} */ public final > Flux buffer(int maxSize, int skip, Supplier bufferSupplier) { return onAssembly(new FluxBuffer<>(this, maxSize, skip, bufferSupplier)); } /** * Collect incoming values into multiple {@link List} buffers, as delimited by the * signals of a companion {@link Publisher} this operator will subscribe to. *

* * * @param other the companion {@link Publisher} whose signals trigger new buffers * * @return a microbatched {@link Flux} of {@link List} delimited by signals from a {@link Publisher} */ public final Flux> buffer(Publisher other) { return buffer(other, listSupplier()); } /** * Collect incoming values into multiple user-defined {@link Collection} buffers, as * delimited by the signals of a companion {@link Publisher} this operator will * subscribe to. *

* * * @param other the companion {@link Publisher} whose signals trigger new buffers * @param bufferSupplier a {@link Supplier} of the concrete {@link Collection} to use for each buffer * @param the {@link Collection} buffer type * * @return a microbatched {@link Flux} of {@link Collection} delimited by signals from a {@link Publisher} */ public final > Flux buffer(Publisher other, Supplier bufferSupplier) { return onAssembly(new FluxBufferBoundary<>(this, other, bufferSupplier)); } /** * Collect incoming values into multiple {@link List} buffers that will be emitted by * the returned {@link Flux} every {@code timespan}. *

* * * @param timespan the duration from buffer creation until a buffer is closed and emitted * * @return a microbatched {@link Flux} of {@link List} delimited by the given time span */ public final Flux> buffer(Duration timespan) { return buffer(timespan, Schedulers.parallel()); } /** * Collect incoming values into multiple {@link List} buffers created at a given * {@code timeshift} period. Each buffer will last until the {@code timespan} has elapsed, * thus emitting the bucket in the resulting {@link Flux}. *

* When timespan < timeshift : dropping buffers *

* *

* When timespan > timeshift : overlapping buffers *

* *

* When timespan == timeshift : exact buffers *

* * * @param timespan the duration from buffer creation until a buffer is closed and emitted * @param timeshift the interval at which to create a new buffer * * @return a microbatched {@link Flux} of {@link List} delimited by the given period timeshift and sized by timespan */ public final Flux> buffer(Duration timespan, Duration timeshift) { return buffer(timespan, timeshift, Schedulers.parallel()); } /** * Collect incoming values into multiple {@link List} buffers that will be emitted by * the returned {@link Flux} every {@code timespan}, as measured on the provided {@link Scheduler}. *

* * * @param timespan the duration from buffer creation until a buffer is closed and emitted * @param timer a time-capable {@link Scheduler} instance to run on * * @return a microbatched {@link Flux} of {@link List} delimited by the given period */ public final Flux> buffer(Duration timespan, Scheduler timer) { return buffer(interval(timespan, timer)); } /** * Collect incoming values into multiple {@link List} buffers created at a given * {@code timeshift} period, as measured on the provided {@link Scheduler}. Each * buffer will last until the {@code timespan} has elapsed (also measured on the scheduler), * thus emitting the bucket in the resulting {@link Flux}. *

* When timespan < timeshift : dropping buffers *

* *

* When timespan > timeshift : overlapping buffers *

* *

* When timespan == timeshift : exact buffers *

* * * @param timespan the duration from buffer creation until a buffer is closed and emitted * @param timeshift the interval at which to create a new buffer * @param timer a time-capable {@link Scheduler} instance to run on * * @return a microbatched {@link Flux} of {@link List} delimited by the given period timeshift and sized by timespan */ public final Flux> buffer(Duration timespan, Duration timeshift, Scheduler timer) { if (timespan.equals(timeshift)) { return buffer(timespan, timer); } return bufferWhen(interval(Duration.ZERO, timeshift, timer), aLong -> Mono .delay(timespan, timer)); } /** * Collect incoming values into multiple {@link List} buffers that will be emitted * by the returned {@link Flux} each time the buffer reaches a maximum size OR the * timespan {@link Duration} elapses. *

* * * @param maxSize the max collected size * @param timespan the timeout enforcing the release of a partial buffer * * @return a microbatched {@link Flux} of {@link List} delimited by given size or a given period timeout */ public final Flux> bufferTimeout(int maxSize, Duration timespan) { return bufferTimeout(maxSize, timespan, listSupplier()); } /** * Collect incoming values into multiple user-defined {@link Collection} buffers that * will be emitted by the returned {@link Flux} each time the buffer reaches a maximum * size OR the timespan {@link Duration} elapses. *

* * * @param maxSize the max collected size * @param timespan the timeout enforcing the release of a partial buffer * @param bufferSupplier a {@link Supplier} of the concrete {@link Collection} to use for each buffer * @param the {@link Collection} buffer type * @return a microbatched {@link Flux} of {@link Collection} delimited by given size or a given period timeout */ public final > Flux bufferTimeout(int maxSize, Duration timespan, Supplier bufferSupplier) { return bufferTimeout(maxSize, timespan, Schedulers.parallel(), bufferSupplier); } /** * Collect incoming values into multiple {@link List} buffers that will be emitted * by the returned {@link Flux} each time the buffer reaches a maximum size OR the * timespan {@link Duration} elapses, as measured on the provided {@link Scheduler}. *

* * * @param maxSize the max collected size * @param timespan the timeout enforcing the release of a partial buffer * @param timer a time-capable {@link Scheduler} instance to run on * * @return a microbatched {@link Flux} of {@link List} delimited by given size or a given period timeout */ public final Flux> bufferTimeout(int maxSize, Duration timespan, Scheduler timer) { return bufferTimeout(maxSize, timespan, timer, listSupplier()); } /** * Collect incoming values into multiple user-defined {@link Collection} buffers that * will be emitted by the returned {@link Flux} each time the buffer reaches a maximum * size OR the timespan {@link Duration} elapses, as measured on the provided {@link Scheduler}. *

* * * @param maxSize the max collected size * @param timespan the timeout enforcing the release of a partial buffer * @param timer a time-capable {@link Scheduler} instance to run on * @param bufferSupplier a {@link Supplier} of the concrete {@link Collection} to use for each buffer * @param the {@link Collection} buffer type * @return a microbatched {@link Flux} of {@link Collection} delimited by given size or a given period timeout */ public final > Flux bufferTimeout(int maxSize, Duration timespan, Scheduler timer, Supplier bufferSupplier) { return onAssembly(new FluxBufferTimeout<>(this, maxSize, timespan.toMillis(), timer, bufferSupplier)); } /** * Collect incoming values into multiple {@link List} buffers that will be emitted by * the resulting {@link Flux} each time the given predicate returns true. Note that * the element that triggers the predicate to return true (and thus closes a buffer) * is included as last element in the emitted buffer. *

* *

* On completion, if the latest buffer is non-empty and has not been closed it is * emitted. However, such a "partial" buffer isn't emitted in case of onError * termination. * * @param predicate a predicate that triggers the next buffer when it becomes true. * @return a microbatched {@link Flux} of {@link List} */ public final Flux> bufferUntil(Predicate predicate) { return onAssembly(new FluxBufferPredicate<>(this, predicate, listSupplier(), FluxBufferPredicate.Mode.UNTIL)); } /** * Collect incoming values into multiple {@link List} buffers that will be emitted by * the resulting {@link Flux} each time the given predicate returns true. Note that * the buffer into which the element that triggers the predicate to return true * (and thus closes a buffer) is included depends on the {@code cutBefore} parameter: * push it to true to include the boundary element in the newly opened buffer, false to * include it in the closed buffer (as in {@link #bufferUntil(Predicate)}). *

* *

* On completion, if the latest buffer is non-empty and has not been closed it is * emitted. However, such a "partial" buffer isn't emitted in case of onError * termination. * * @param predicate a predicate that triggers the next buffer when it becomes true. * @param cutBefore push to true to include the triggering element in the new buffer rather than the old. * @return a microbatched {@link Flux} of {@link List} */ public final Flux> bufferUntil(Predicate predicate, boolean cutBefore) { return onAssembly(new FluxBufferPredicate<>(this, predicate, listSupplier(), cutBefore ? FluxBufferPredicate.Mode.UNTIL_CUT_BEFORE : FluxBufferPredicate.Mode.UNTIL)); } /** * Collect incoming values into multiple {@link List} buffers that will be emitted by * the resulting {@link Flux}. Each buffer continues aggregating values while the * given predicate returns true, and a new buffer is created as soon as the * predicate returns false... Note that the element that triggers the predicate * to return false (and thus closes a buffer) is NOT included in any emitted buffer. *

* *

* On completion, if the latest buffer is non-empty and has not been closed it is * emitted. However, such a "partial" buffer isn't emitted in case of onError * termination. * * @param predicate a predicate that triggers the next buffer when it becomes false. * @return a microbatched {@link Flux} of {@link List} */ public final Flux> bufferWhile(Predicate predicate) { return onAssembly(new FluxBufferPredicate<>(this, predicate, listSupplier(), FluxBufferPredicate.Mode.WHILE)); } /** * Collect incoming values into multiple {@link List} buffers started each time an opening * companion {@link Publisher} emits. Each buffer will last until the corresponding * closing companion {@link Publisher} emits, thus releasing the buffer to the resulting {@link Flux}. *

* When Open signal is strictly not overlapping Close signal : dropping buffers *

* *

* When Open signal is strictly more frequent than Close signal : overlapping buffers *

* *

* When Open signal is exactly coordinated with Close signal : exact buffers *

* * * @param bucketOpening a companion {@link Publisher} to subscribe for buffer creation signals. * @param closeSelector a factory that, given a buffer opening signal, returns a companion * {@link Publisher} to subscribe to for buffer closure and emission signals. * @param the element type of the buffer-opening sequence * @param the element type of the buffer-closing sequence * * @return a microbatched {@link Flux} of {@link List} delimited by an opening {@link Publisher} and a relative * closing {@link Publisher} */ public final Flux> bufferWhen(Publisher bucketOpening, Function> closeSelector) { return bufferWhen(bucketOpening, closeSelector, listSupplier()); } /** * Collect incoming values into multiple user-defined {@link Collection} buffers started each time an opening * companion {@link Publisher} emits. Each buffer will last until the corresponding * closing companion {@link Publisher} emits, thus releasing the buffer to the resulting {@link Flux}. *

* When Open signal is strictly not overlapping Close signal : dropping buffers *

* *

* When Open signal is strictly more frequent than Close signal : overlapping buffers *

* *

* When Open signal is exactly coordinated with Close signal : exact buffers *

* * * @param bucketOpening a companion {@link Publisher} to subscribe for buffer creation signals. * @param closeSelector a factory that, given a buffer opening signal, returns a companion * {@link Publisher} to subscribe to for buffer closure and emission signals. * @param bufferSupplier a {@link Supplier} of the concrete {@link Collection} to use for each buffer * @param the element type of the buffer-opening sequence * @param the element type of the buffer-closing sequence * @param the {@link Collection} buffer type * * @return a microbatched {@link Flux} of {@link Collection} delimited by an opening {@link Publisher} and a relative * closing {@link Publisher} */ public final > Flux bufferWhen(Publisher bucketOpening, Function> closeSelector, Supplier bufferSupplier) { return onAssembly(new FluxBufferWhen<>(this, bucketOpening, closeSelector, bufferSupplier, Queues.unbounded(Queues.XS_BUFFER_SIZE))); } /** * Turn this {@link Flux} into a hot source and cache last emitted signals for further {@link Subscriber}. Will * retain an unbounded volume of onNext signals. Completion and Error will also be * replayed. *

* * * @return a replaying {@link Flux} */ public final Flux cache() { return cache(Integer.MAX_VALUE); } /** * Turn this {@link Flux} into a hot source and cache last emitted signals for further {@link Subscriber}. * Will retain up to the given history size onNext signals. Completion and Error will also be * replayed. *

* Note that {@code cache(0)} will only cache the terminal signal without * expiration. *

* * * @param history number of elements retained in cache * * @return a replaying {@link Flux} * */ public final Flux cache(int history) { return replay(history).autoConnect(); } /** * Turn this {@link Flux} into a hot source and cache last emitted signals for further * {@link Subscriber}. Will retain an unbounded history but apply a per-item expiry timeout *

* Completion and Error will also be replayed until {@code ttl} triggers in which case * the next {@link Subscriber} will start over a new subscription. *

* * * @param ttl Time-to-live for each cached item and post termination. * * @return a replaying {@link Flux} */ public final Flux cache(Duration ttl) { return replay(Integer.MAX_VALUE, ttl).autoConnect(); } /** * Turn this {@link Flux} into a hot source and cache last emitted signals for further * {@link Subscriber}. Will retain up to the given history size and apply a per-item expiry * timeout. *

* Completion and Error will also be replayed until {@code ttl} triggers in which case * the next {@link Subscriber} will start over a new subscription. *

* * * @param history number of elements retained in cache * @param ttl Time-to-live for each cached item and post termination. * * @return a replaying {@link Flux} */ public final Flux cache(int history, Duration ttl) { return replay(history, ttl).autoConnect(); } /** * Cast the current {@link Flux} produced type into a target produced type. * *

* * * @param the {@link Flux} output type * @param clazz the target class to cast to * * @return a casted {@link Flux} */ public final Flux cast(Class clazz) { Objects.requireNonNull(clazz, "clazz"); return map(clazz::cast); } /** * Prepare this {@link Flux} so that subscribers will cancel from it on a * specified * {@link Scheduler}. * * @param scheduler the {@link Scheduler} to signal cancel on * * @return a scheduled cancel {@link Flux} */ public final Flux cancelOn(Scheduler scheduler) { return onAssembly(new FluxCancelOn<>(this, scheduler)); } /** * Activate assembly tracing for this particular {@link Flux}, in case of an error * upstream of the checkpoint. Tracing incurs the cost of an exception stack trace * creation. *

* It should be placed towards the end of the reactive chain, as errors * triggered downstream of it cannot be observed and augmented with assembly trace. * * @return the assembly tracing {@link Flux}. */ public final Flux checkpoint() { return checkpoint(null, true); } /** * Activate assembly marker for this particular {@link Flux} by giving it a description that * will be reflected in the assembly traceback in case of an error upstream of the * checkpoint. Note that unlike {@link #checkpoint()}, this doesn't create a * filled stack trace, avoiding the main cost of the operator. * However, as a trade-off the description must be unique enough for the user to find * out where this Flux was assembled. If you only want a generic description, and * still rely on the stack trace to find the assembly site, use the * {@link #checkpoint(String, boolean)} variant. *

* It should be placed towards the end of the reactive chain, as errors * triggered downstream of it cannot be observed and augmented with assembly trace. * * @param description a unique enough description to include in the light assembly traceback. * @return the assembly marked {@link Flux} */ public final Flux checkpoint(String description) { return checkpoint(Objects.requireNonNull(description), false); } /** * Activate assembly tracing or the lighter assembly marking depending on the * {@code forceStackTrace} option. *

* By setting the {@code forceStackTrace} parameter to {@literal true}, activate assembly * tracing for this particular {@link Flux} and give it a description that * will be reflected in the assembly traceback in case of an error upstream of the * checkpoint. Note that unlike {@link #checkpoint(String)}, this will incur * the cost of an exception stack trace creation. The description could for * example be a meaningful name for the assembled flux or a wider correlation ID, * since the stack trace will always provide enough information to locate where this * Flux was assembled. *

* By setting {@code forceStackTrace} to {@literal false}, behaves like * {@link #checkpoint(String)} and is subject to the same caveat in choosing the * description. *

* It should be placed towards the end of the reactive chain, as errors * triggered downstream of it cannot be observed and augmented with assembly marker. * * @param description a description (must be unique enough if forceStackTrace is push * to false). * @param forceStackTrace false to make a light checkpoint without a stacktrace, true * to use a stack trace. * @return the assembly marked {@link Flux}. */ public final Flux checkpoint(@Nullable String description, boolean forceStackTrace) { return new FluxOnAssembly<>(this, description, !forceStackTrace); } /** * Collect all elements emitted by this {@link Flux} into a user-defined container, * by applying a collector {@link BiConsumer} taking the container and each element. * The collected result will be emitted when this sequence completes. * *

* * * @param the container type * @param containerSupplier the supplier of the container instance for each Subscriber * @param collector a consumer of both the container instance and the value being currently collected * * @return a {@link Mono} of the collected container on complete * */ public final Mono collect(Supplier containerSupplier, BiConsumer collector) { return Mono.onAssembly(new MonoCollect<>(this, containerSupplier, collector)); } /** * Collect all elements emitted by this {@link Flux} into a container, * by applying a Java 8 Stream API {@link Collector} * The collected result will be emitted when this sequence completes. * *

* * * @param collector the {@link Collector} * @param The mutable accumulation type * @param the container type * * @return a {@link Mono} of the collected container on complete * */ public final Mono collect(Collector collector) { return Mono.onAssembly(new MonoStreamCollector<>(this, collector)); } /** * Collect all elements emitted by this {@link Flux} into a {@link List} that is * emitted by the resulting {@link Mono} when this sequence completes. * *

* * * @return a {@link Mono} of a {@link List} of all values from this {@link Flux} */ public final Mono> collectList() { if (this instanceof Callable) { if (this instanceof Fuseable.ScalarCallable) { @SuppressWarnings("unchecked") Fuseable.ScalarCallable scalarCallable = (Fuseable.ScalarCallable) this; T v; try { v = scalarCallable.call(); } catch (Exception e) { return Mono.error(e); } if (v == null) { return Mono.onAssembly(new MonoSupplier<>(listSupplier())); } return Mono.just(v).map(u -> { List list = Flux.listSupplier().get(); list.add(u); return list; }); } @SuppressWarnings("unchecked") Callable thiz = (Callable)this; return Mono.onAssembly(new MonoCallable<>(thiz).map(u -> { List list = Flux.listSupplier().get(); list.add(u); return list; })); } return Mono.onAssembly(new MonoCollectList<>(this, listSupplier())); } /** * Collect all elements emitted by this {@link Flux} into a hashed {@link Map} that is * emitted by the resulting {@link Mono} when this sequence completes. * The key is extracted from each element by applying the {@code keyExtractor} * {@link Function}. In case several elements map to the same key, the associated value * will be the most recently emitted element. * *

* * * @param keyExtractor a {@link Function} to map elements to a key for the {@link Map} * @param the type of the key extracted from each source element * * @return a {@link Mono} of a {@link Map} of key-element pairs (only including latest * element in case of key conflicts) * */ public final Mono> collectMap(Function keyExtractor) { return collectMap(keyExtractor, identityFunction()); } /** * Collect all elements emitted by this {@link Flux} into a hashed {@link Map} that is * emitted by the resulting {@link Mono} when this sequence completes. * The key is extracted from each element by applying the {@code keyExtractor} * {@link Function}, and the value is extracted by the {@code valueExtractor} Function. * In case several elements map to the same key, the associated value will be derived * from the most recently emitted element. * *

* * * @param keyExtractor a {@link Function} to map elements to a key for the {@link Map} * @param valueExtractor a {@link Function} to map elements to a value for the {@link Map} * * @param the type of the key extracted from each source element * @param the type of the value extracted from each source element * * @return a {@link Mono} of a {@link Map} of key-element pairs (only including latest * element's value in case of key conflicts) */ public final Mono> collectMap(Function keyExtractor, Function valueExtractor) { return collectMap(keyExtractor, valueExtractor, () -> new HashMap<>()); } /** * Collect all elements emitted by this {@link Flux} into a user-defined {@link Map} that is * emitted by the resulting {@link Mono} when this sequence completes. * The key is extracted from each element by applying the {@code keyExtractor} * {@link Function}, and the value is extracted by the {@code valueExtractor} Function. * In case several elements map to the same key, the associated value will be derived * from the most recently emitted element. * *

* * * @param keyExtractor a {@link Function} to map elements to a key for the {@link Map} * @param valueExtractor a {@link Function} to map elements to a value for the {@link Map} * @param mapSupplier a {@link Map} factory called for each {@link Subscriber} * * @param the type of the key extracted from each source element * @param the type of the value extracted from each source element * * @return a {@link Mono} of a {@link Map} of key-value pairs (only including latest * element's value in case of key conflicts) */ public final Mono> collectMap( final Function keyExtractor, final Function valueExtractor, Supplier> mapSupplier) { Objects.requireNonNull(keyExtractor, "Key extractor is null"); Objects.requireNonNull(valueExtractor, "Value extractor is null"); Objects.requireNonNull(mapSupplier, "Map supplier is null"); return collect(mapSupplier, (m, d) -> m.put(keyExtractor.apply(d), valueExtractor.apply(d))); } /** * Collect all elements emitted by this {@link Flux} into a {@link Map multimap} that is * emitted by the resulting {@link Mono} when this sequence completes. * The key is extracted from each element by applying the {@code keyExtractor} * {@link Function}, and every element mapping to the same key is stored in the {@link List} * associated to said key. * *

* * * @param keyExtractor a {@link Function} to map elements to a key for the {@link Map} * * @param the type of the key extracted from each source element * @return a {@link Mono} of a {@link Map} of key-List(elements) pairs */ public final Mono>> collectMultimap(Function keyExtractor) { return collectMultimap(keyExtractor, identityFunction()); } /** * Collect all elements emitted by this {@link Flux} into a {@link Map multimap} that is * emitted by the resulting {@link Mono} when this sequence completes. * The key is extracted from each element by applying the {@code keyExtractor} * {@link Function}, and every element mapping to the same key is converted by the * {@code valueExtractor} Function to a value stored in the {@link List} associated to * said key. * *

* * * @param keyExtractor a {@link Function} to map elements to a key for the {@link Map} * @param valueExtractor a {@link Function} to map elements to a value for the {@link Map} * * @param the type of the key extracted from each source element * @param the type of the value extracted from each source element * * @return a {@link Mono} of a {@link Map} of key-List(values) pairs */ public final Mono>> collectMultimap(Function keyExtractor, Function valueExtractor) { return collectMultimap(keyExtractor, valueExtractor, () -> new HashMap<>()); } /** * Collect all elements emitted by this {@link Flux} into a user-defined {@link Map multimap} that is * emitted by the resulting {@link Mono} when this sequence completes. * The key is extracted from each element by applying the {@code keyExtractor} * {@link Function}, and every element mapping to the same key is converted by the * {@code valueExtractor} Function to a value stored in the {@link Collection} associated to * said key. * *

* * * @param keyExtractor a {@link Function} to map elements to a key for the {@link Map} * @param valueExtractor a {@link Function} to map elements to a value for the {@link Map} * @param mapSupplier a multimap ({@link Map} of {@link Collection}) factory called * for each {@link Subscriber} * * @param the type of the key extracted from each source element * @param the type of the value extracted from each source element * * @return a {@link Mono} of a {@link Map} of key-Collection(values) pairs * */ public final Mono>> collectMultimap( final Function keyExtractor, final Function valueExtractor, Supplier>> mapSupplier) { Objects.requireNonNull(keyExtractor, "Key extractor is null"); Objects.requireNonNull(valueExtractor, "Value extractor is null"); Objects.requireNonNull(mapSupplier, "Map supplier is null"); return collect(mapSupplier, (m, d) -> { K key = keyExtractor.apply(d); Collection values = m.computeIfAbsent(key, k -> new ArrayList<>()); values.add(valueExtractor.apply(d)); }); } /** * Collect all elements emitted by this {@link Flux} until this sequence completes, * and then sort them in natural order into a {@link List} that is emitted by the * resulting {@link Mono}. * *

* * * @return a {@link Mono} of a sorted {@link List} of all values from this {@link Flux}, in natural order */ public final Mono> collectSortedList() { return collectSortedList(null); } /** * Collect all elements emitted by this {@link Flux} until this sequence completes, * and then sort them using a {@link Comparator} into a {@link List} that is emitted * by the resulting {@link Mono}. * *

* * * @param comparator a {@link Comparator} to sort the items of this sequences * * @return a {@link Mono} of a sorted {@link List} of all values from this {@link Flux} */ @SuppressWarnings({ "unchecked", "rawtypes" }) public final Mono> collectSortedList(@Nullable Comparator comparator) { return collectList().map(list -> { // Note: this assumes the list emitted by buffer() is mutable if (comparator != null) { list.sort(comparator); } else { List l = (List)list; Collections.sort(l); } return list; }); } /** * Defer the transformation of this {@link Flux} in order to generate a target {@link Flux} type. * A transformation will occur for each {@link Subscriber}. For instance: *

	 * {@code flux.compose(Mono::from).subscribe() }
	 * 
* * @param transformer the {@link Function} to lazily map this {@link Flux} into a target {@link Publisher} * instance for each new subscriber * @param the item type in the returned {@link Publisher} * * @return a new {@link Flux} * @see #transform transform() for immmediate transformation of {@link Flux} * @see #as as() for a loose conversion to an arbitrary type */ public final Flux compose(Function, ? extends Publisher> transformer) { return defer(() -> transformer.apply(this)); } /** * Transform the elements emitted by this {@link Flux} asynchronously into Publishers, * then flatten these inner publishers into a single {@link Flux}, sequentially and * preserving order using concatenation. *

* There are three dimensions to this operator that can be compared with * {@link #flatMap(Function) flatMap} and {@link #flatMapSequential(Function) flatMapSequential}: *

    *
  • Generation of inners and subscription: this operator waits for one * inner to complete before generating the next one and subscribing to it.
  • *
  • Ordering of the flattened values: this operator naturally preserves * the same order as the source elements, concatenating the inners from each source * element sequentially.
  • *
  • Interleaving: this operator does not let values from different inners * interleave (concatenation).
  • *
* *

* Errors will immediately short circuit current concat backlog. * *

* * * @param mapper the function to transform this sequence of T into concatenated sequences of V * @param the produced concatenated type * * @return a concatenated {@link Flux} */ public final Flux concatMap(Function> mapper) { return concatMap(mapper, Queues.XS_BUFFER_SIZE); } /** * Transform the elements emitted by this {@link Flux} asynchronously into Publishers, * then flatten these inner publishers into a single {@link Flux}, sequentially and * preserving order using concatenation. *

* There are three dimensions to this operator that can be compared with * {@link #flatMap(Function) flatMap} and {@link #flatMapSequential(Function) flatMapSequential}: *

    *
  • Generation of inners and subscription: this operator waits for one * inner to complete before generating the next one and subscribing to it.
  • *
  • Ordering of the flattened values: this operator naturally preserves * the same order as the source elements, concatenating the inners from each source * element sequentially.
  • *
  • Interleaving: this operator does not let values from different inners * interleave (concatenation).
  • *
* *

* Errors will immediately short circuit current concat backlog. The prefetch argument * allows to give an arbitrary prefetch size to the inner {@link Publisher}. * *

* * * @param mapper the function to transform this sequence of T into concatenated sequences of V * @param prefetch the inner source produced demand * @param the produced concatenated type * * @return a concatenated {@link Flux} */ public final Flux concatMap(Function> mapper, int prefetch) { return onAssembly(new FluxConcatMap<>(this, mapper, Queues.get(prefetch), prefetch, FluxConcatMap.ErrorMode.IMMEDIATE)); } /** * Transform the elements emitted by this {@link Flux} asynchronously into Publishers, * then flatten these inner publishers into a single {@link Flux}, sequentially and * preserving order using concatenation. *

* There are three dimensions to this operator that can be compared with * {@link #flatMap(Function) flatMap} and {@link #flatMapSequential(Function) flatMapSequential}: *

    *
  • Generation of inners and subscription: this operator waits for one * inner to complete before generating the next one and subscribing to it.
  • *
  • Ordering of the flattened values: this operator naturally preserves * the same order as the source elements, concatenating the inners from each source * element sequentially.
  • *
  • Interleaving: this operator does not let values from different inners * interleave (concatenation).
  • *
* *

* Errors will be delayed after all concatenated sources terminate. * *

* * * * @param mapper the function to transform this sequence of T into concatenated sequences of V * @param the produced concatenated type * * @return a concatenated {@link Flux} * */ public final Flux concatMapDelayError(Function> mapper) { return concatMapDelayError(mapper, Queues.XS_BUFFER_SIZE); } /** * Transform the elements emitted by this {@link Flux} asynchronously into Publishers, * then flatten these inner publishers into a single {@link Flux}, sequentially and * preserving order using concatenation. *

* There are three dimensions to this operator that can be compared with * {@link #flatMap(Function) flatMap} and {@link #flatMapSequential(Function) flatMapSequential}: *

    *
  • Generation of inners and subscription: this operator waits for one * inner to complete before generating the next one and subscribing to it.
  • *
  • Ordering of the flattened values: this operator naturally preserves * the same order as the source elements, concatenating the inners from each source * element sequentially.
  • *
  • Interleaving: this operator does not let values from different inners * interleave (concatenation).
  • *
* *

* Errors will be delayed after all concatenated sources terminate. The prefetch argument * allows to give an arbitrary prefetch size to the inner {@link Publisher}. * *

* * * * @param mapper the function to transform this sequence of T into concatenated sequences of V * @param prefetch the inner source produced demand * @param the produced concatenated type * * @return a concatenated {@link Flux} * */ public final Flux concatMapDelayError(Function> mapper, int prefetch) { return onAssembly(new FluxConcatMap<>(this, mapper, Queues.get(prefetch), prefetch, FluxConcatMap.ErrorMode.BOUNDARY)); } /** * Transform the elements emitted by this {@link Flux} asynchronously into Publishers, * then flatten these inner publishers into a single {@link Flux}, sequentially and * preserving order using concatenation. *

* There are three dimensions to this operator that can be compared with * {@link #flatMap(Function) flatMap} and {@link #flatMapSequential(Function) flatMapSequential}: *

    *
  • Generation of inners and subscription: this operator waits for one * inner to complete before generating the next one and subscribing to it.
  • *
  • Ordering of the flattened values: this operator naturally preserves * the same order as the source elements, concatenating the inners from each source * element sequentially.
  • *
  • Interleaving: this operator does not let values from different inners * interleave (concatenation).
  • *
* *

* Errors will be delayed after the current concat backlog if delayUntilEnd is * false or after all sources if delayUntilEnd is true. The prefetch argument * allows to give an arbitrary prefetch size to the inner {@link Publisher}. * *

* * * * @param mapper the function to transform this sequence of T into concatenated sequences of V * @param delayUntilEnd delay error until all sources have been consumed instead of * after the current source * @param prefetch the inner source produced demand * @param the produced concatenated type * * @return a concatenated {@link Flux} * */ public final Flux concatMapDelayError(Function> mapper, boolean delayUntilEnd, int prefetch) { return onAssembly(new FluxConcatMap<>(this, mapper, Queues.get(prefetch), prefetch, delayUntilEnd ? FluxConcatMap.ErrorMode.END : FluxConcatMap.ErrorMode .BOUNDARY)); } /** * Transform the items emitted by this {@link Flux} into {@link Iterable}, then flatten the elements from those by * concatenating them into a single {@link Flux}. * *

* *

* Note that unlike {@link #flatMap(Function)} and {@link #concatMap(Function)}, with Iterable there is * no notion of eager vs lazy inner subscription. The content of the Iterables are all played sequentially. * Thus {@code flatMapIterable} and {@code concatMapIterable} are equivalent offered as a discoverability * improvement for users that explore the API with the concat vs flatMap expectation. * * @param mapper the {@link Function} to transform input sequence into N {@link Iterable} * @param the merged output sequence type * * @return a concatenation of the values from the Iterables obtained from each element in this {@link Flux} */ public final Flux concatMapIterable(Function> mapper) { return concatMapIterable(mapper, Queues.XS_BUFFER_SIZE); } /** * Transform the items emitted by this {@link Flux} into {@link Iterable}, then flatten the emissions from those by * concatenating them into a single {@link Flux}. The prefetch argument allows to give an arbitrary prefetch size to the merged {@link Iterable}. * *

* *

* Note that unlike {@link #flatMap(Function)} and {@link #concatMap(Function)}, with Iterable there is * no notion of eager vs lazy inner subscription. The content of the Iterables are all played sequentially. * Thus {@code flatMapIterable} and {@code concatMapIterable} are equivalent offered as a discoverability * improvement for users that explore the API with the concat vs flatMap expectation. * * @param mapper the {@link Function} to transform input sequence into N {@link Iterable} * @param prefetch the maximum in-flight elements from each inner {@link Iterable} sequence * @param the merged output sequence type * * @return a concatenation of the values from the Iterables obtained from each element in this {@link Flux} */ public final Flux concatMapIterable(Function> mapper, int prefetch) { return onAssembly(new FluxFlattenIterable<>(this, mapper, prefetch, Queues.get(prefetch))); } /** * Concatenate emissions of this {@link Flux} with the provided {@link Publisher} (no interleave). *

* * * @param other the {@link Publisher} sequence to concat after this {@link Flux} * * @return a concatenated {@link Flux} */ public final Flux concatWith(Publisher other) { if (this instanceof FluxConcatArray) { @SuppressWarnings({ "unchecked" }) FluxConcatArray fluxConcatArray = (FluxConcatArray) this; return fluxConcatArray.concatAdditionalSourceLast(other); } return concat(this, other); } /** * Counts the number of values in this {@link Flux}. * The count will be emitted when onComplete is observed. * *

* * * @return a new {@link Mono} of {@link Long} count */ public final Mono count() { return Mono.onAssembly(new MonoCount<>(this)); } /** * Provide a default unique value if this sequence is completed without any data *

* *

* @param defaultV the alternate value if this sequence is empty * * @return a new {@link Flux} */ public final Flux defaultIfEmpty(T defaultV) { return onAssembly(new FluxDefaultIfEmpty<>(this, defaultV)); } /** * Delay each of this {@link Flux} elements ({@link Subscriber#onNext} signals) * by a given {@link Duration}. Signals are delayed and continue on the * {@link Schedulers#parallel() parallel} default Scheduler, but empty sequences or * immediate error signals are not delayed. * *

* * * @param delay duration by which to delay each {@link Subscriber#onNext} signal * @return a delayed {@link Flux} * @see #delaySubscription(Duration) delaySubscription to introduce a delay at the beginning of the sequence only */ public final Flux delayElements(Duration delay) { return delayElements(delay, Schedulers.parallel()); } /** * Delay each of this {@link Flux} elements ({@link Subscriber#onNext} signals) * by a given {@link Duration}. Signals are delayed and continue on an user-specified * {@link Scheduler}, but empty sequences or immediate error signals are not delayed. * *

* * * @param delay period to delay each {@link Subscriber#onNext} signal * @param timer a time-capable {@link Scheduler} instance to delay each signal on * @return a delayed {@link Flux} */ public final Flux delayElements(Duration delay, Scheduler timer) { return delayUntil(d -> Mono.delay(delay, timer)); } /** * Subscribe to this {@link Flux} and generate a {@link Publisher} from each of this * Flux elements, each acting as a trigger for relaying said element. *

* That is to say, the resulting {@link Flux} delays each of its emission until the * associated trigger Publisher terminates. *

* In case of an error either in the source or in a trigger, that error is propagated * immediately downstream. * Note that unlike with the {@link Mono#delayUntil(Function) Mono variant} there is * no fusion of subsequent calls. *

* * * @param triggerProvider a {@link Function} that maps each element into a * {@link Publisher} whose termination will trigger relaying the value. * * @return this Flux, but with elements delayed until their derived publisher terminates. */ public final Flux delayUntil(Function> triggerProvider) { return concatMap(v -> Mono.just(v) .delayUntil(triggerProvider)); } /** * Delay the {@link Flux#subscribe(Subscriber) subscription} to this {@link Flux} source until the given * period elapses. The delay is introduced through the {@link Schedulers#parallel() parallel} default Scheduler. * *

* * * @param delay duration before subscribing this {@link Flux} * * @return a delayed {@link Flux} * */ public final Flux delaySubscription(Duration delay) { return delaySubscription(delay, Schedulers.parallel()); } /** * Delay the {@link Flux#subscribe(Subscriber) subscription} to this {@link Flux} source until the given * period elapses, as measured on the user-provided {@link Scheduler}. * *

* * * @param delay {@link Duration} before subscribing this {@link Flux} * @param timer a time-capable {@link Scheduler} instance to run on * * @return a delayed {@link Flux} */ public final Flux delaySubscription(Duration delay, Scheduler timer) { return delaySubscription(Mono.delay(delay, timer)); } /** * Delay the {@link Flux#subscribe(Subscriber) subscription} to this {@link Flux} * source until another {@link Publisher} signals a value or completes. * *

* * * @param subscriptionDelay a companion {@link Publisher} whose onNext/onComplete signal will trigger the {@link Flux#subscribe(Subscriber) subscription} * @param the other source type * * @return a delayed {@link Flux} * */ public final Flux delaySubscription(Publisher subscriptionDelay) { return onAssembly(new FluxDelaySubscription<>(this, subscriptionDelay)); } /** * An operator working only if this {@link Flux} emits onNext, onError or onComplete {@link Signal} * instances, transforming these {@link #materialize() materialized} signals into * real signals on the {@link Subscriber}. * The error {@link Signal} will trigger onError and complete {@link Signal} will trigger * onComplete. * *

* * * @param the dematerialized type * * @return a dematerialized {@link Flux} * @see #materialize() */ public final Flux dematerialize() { @SuppressWarnings("unchecked") Flux> thiz = (Flux>) this; return onAssembly(new FluxDematerialize<>(thiz)); } /** * For each {@link Subscriber}, track elements from this {@link Flux} that have been * seen and filter out duplicates. * *

* * * @return a filtering {@link Flux} only emitting distinct values */ public final Flux distinct() { return distinct(hashcodeSupplier()); } /** * For each {@link Subscriber}, track elements from this {@link Flux} that have been * seen and filter out duplicates, as compared by a key extracted through the user * provided {@link Function}. * *

* * * @param keySelector function to compute comparison key for each element * @param the type of the key extracted from each value in this sequence * * @return a filtering {@link Flux} only emitting values with distinct keys */ public final Flux distinct(Function keySelector) { return distinct(keySelector, hashSetSupplier()); } /** * For each {@link Subscriber}, track elements from this {@link Flux} that have been * seen and filter out duplicates, as compared by a key extracted through the user * provided {@link Function} and by the {@link Collection#add(Object) add method} * of the {@link Collection} supplied (typically a {@link Set}). * *

* * * @param keySelector function to compute comparison key for each element * @param distinctCollectionSupplier supplier of the {@link Collection} used for distinct * check through {@link Collection#add(Object) add} of the key. * * @param the type of the key extracted from each value in this sequence * @param the type of Collection used for distinct checking of keys * * @return a filtering {@link Flux} only emitting values with distinct keys */ public final > Flux distinct( Function keySelector, Supplier distinctCollectionSupplier) { if (this instanceof Fuseable) { return onAssembly(new FluxDistinctFuseable<>(this, keySelector, distinctCollectionSupplier)); } return onAssembly(new FluxDistinct<>(this, keySelector, distinctCollectionSupplier)); } /** * Filter out subsequent repetitions of an element (that is, if they arrive right after * one another). * *

* * * @return a filtering {@link Flux} with only one occurrence in a row of each element * (yet elements can repeat in the overall sequence) */ public final Flux distinctUntilChanged() { return distinctUntilChanged(hashcodeSupplier()); } /** * Filter out subsequent repetitions of an element (that is, if they arrive right after * one another), as compared by a key extracted through the user provided {@link Function} * using equality. * *

* * * @param keySelector function to compute comparison key for each element * @param the type of the key extracted from each value in this sequence * * @return a filtering {@link Flux} with only one occurrence in a row of each element of * the same key (yet element keys can repeat in the overall sequence) */ public final Flux distinctUntilChanged(Function keySelector) { return distinctUntilChanged(keySelector, equalPredicate()); } /** * Filter out subsequent repetitions of an element (that is, if they arrive right * after one another), as compared by a key extracted through the user provided {@link * Function} and then comparing keys with the supplied {@link BiPredicate}. *

* * * @param keySelector function to compute comparison key for each element * @param keyComparator predicate used to compare keys. * @param the type of the key extracted from each value in this sequence * * @return a filtering {@link Flux} with only one occurrence in a row of each element * of the same key for which the predicate returns true (yet element keys can repeat * in the overall sequence) */ public final Flux distinctUntilChanged(Function keySelector, BiPredicate keyComparator) { return onAssembly(new FluxDistinctUntilChanged<>(this, keySelector, keyComparator)); } /** * Add behavior (side-effect) triggered after the {@link Flux} terminates, either by completing downstream successfully or with an error. *

* *

* @param afterTerminate the callback to call after {@link Subscriber#onComplete} or {@link Subscriber#onError} * * @return an observed {@link Flux} */ public final Flux doAfterTerminate(Runnable afterTerminate) { Objects.requireNonNull(afterTerminate, "afterTerminate"); return doOnSignal(this, null, null, null, null, afterTerminate, null, null); } /** * Add behavior (side-effect) triggered when the {@link Flux} is cancelled. *

* *

* @param onCancel the callback to call on {@link Subscription#cancel} * * @return an observed {@link Flux} */ public final Flux doOnCancel(Runnable onCancel) { Objects.requireNonNull(onCancel, "onCancel"); return doOnSignal(this, null, null, null, null, null, null, onCancel); } /** * Add behavior (side-effect) triggered when the {@link Flux} completes successfully. *

* *

* @param onComplete the callback to call on {@link Subscriber#onComplete} * * @return an observed {@link Flux} */ public final Flux doOnComplete(Runnable onComplete) { Objects.requireNonNull(onComplete, "onComplete"); return doOnSignal(this, null, null, null, onComplete, null, null, null); } /** * Add behavior (side-effects) triggered when the {@link Flux} emits an item, fails with an error * or completes successfully. All these events are represented as a {@link Signal} * that is passed to the side-effect callback. Note that this is an advanced operator, * typically used for monitoring of a Flux. * * @param signalConsumer the mandatory callback to call on * {@link Subscriber#onNext(Object)}, {@link Subscriber#onError(Throwable)} and * {@link Subscriber#onComplete()} * @return an observed {@link Flux} * @see #doOnNext(Consumer) * @see #doOnError(Consumer) * @see #doOnComplete(Runnable) * @see #materialize() * @see Signal */ public final Flux doOnEach(Consumer> signalConsumer) { return onAssembly(new FluxDoOnEach<>(this, signalConsumer)); } /** * Add behavior (side-effect) triggered when the {@link Flux} completes with an error. *

* *

* @param onError the callback to call on {@link Subscriber#onError} * * @return an observed {@link Flux} */ public final Flux doOnError(Consumer onError) { Objects.requireNonNull(onError, "onError"); return doOnSignal(this, null, null, onError, null, null, null, null); } /** * Add behavior (side-effect) triggered when the {@link Flux} completes with an error matching the given exception type. *

* * * @param exceptionType the type of exceptions to handle * @param onError the error handler for each error * @param type of the error to handle * * @return an observed {@link Flux} * */ public final Flux doOnError(Class exceptionType, final Consumer onError) { Objects.requireNonNull(exceptionType, "type"); @SuppressWarnings("unchecked") Consumer handler = (Consumer)onError; return doOnError(exceptionType::isInstance, (handler)); } /** * Add behavior (side-effect) triggered when the {@link Flux} completes with an error matching the given exception. *

* * * @param predicate the matcher for exceptions to handle * @param onError the error handler for each error * * @return an observed {@link Flux} * */ public final Flux doOnError(Predicate predicate, final Consumer onError) { Objects.requireNonNull(predicate, "predicate"); return doOnError(t -> { if (predicate.test(t)) { onError.accept(t); } }); } /** * Add behavior (side-effect) triggered when the {@link Flux} emits an item. *

* *

* @param onNext the callback to call on {@link Subscriber#onNext} * * @return an observed {@link Flux} */ public final Flux doOnNext(Consumer onNext) { Objects.requireNonNull(onNext, "onNext"); return doOnSignal(this, null, onNext, null, null, null, null, null); } /** * Add behavior (side-effect) triggering a {@link LongConsumer} when this {@link Flux} * receives any request. *

* Note that non fatal error raised in the callback will not be propagated and * will simply trigger {@link Operators#onOperatorError(Throwable, Context)}. * *

* * * @param consumer the consumer to invoke on each request * * @return an observed {@link Flux} */ public final Flux doOnRequest(LongConsumer consumer) { Objects.requireNonNull(consumer, "consumer"); return doOnSignal(this, null, null, null, null, null, consumer, null); } /** * Add behavior (side-effect) triggered when the {@link Flux} is subscribed. *

* *

* @param onSubscribe the callback to call on {@link Subscriber#onSubscribe} * * @return an observed {@link Flux} */ public final Flux doOnSubscribe(Consumer onSubscribe) { Objects.requireNonNull(onSubscribe, "onSubscribe"); return doOnSignal(this, onSubscribe, null, null, null, null, null, null); } /** * Add behavior (side-effect) triggered when the {@link Flux} terminates, either by * completing successfully or with an error. *

* *

* @param onTerminate the callback to call on {@link Subscriber#onComplete} or {@link Subscriber#onError} * * @return an observed {@link Flux} */ public final Flux doOnTerminate(Runnable onTerminate) { Objects.requireNonNull(onTerminate, "onTerminate"); return doOnSignal(this, null, null, e -> onTerminate.run(), onTerminate, null, null, null); } /** * Add behavior (side-effect) triggered after the {@link Flux} terminates for any reason, * including cancellation. The terminating event ({@link SignalType#ON_COMPLETE}, * {@link SignalType#ON_ERROR} and {@link SignalType#CANCEL}) is passed to the consumer, * which is executed after the signal has been passed downstream. *

* Note that the fact that the signal is propagated downstream before the callback is * executed means that several doFinally in a row will be executed in * reverse order. If you want to assert the execution of the callback * please keep in mind that the Flux will complete before it is executed, so its * effect might not be visible immediately after eg. a {@link #blockLast()}. * * @param onFinally the callback to execute after a terminal signal (complete, error * or cancel) * @return an observed {@link Flux} */ public final Flux doFinally(Consumer onFinally) { Objects.requireNonNull(onFinally, "onFinally"); if (this instanceof Fuseable) { return onAssembly(new FluxDoFinallyFuseable<>(this, onFinally)); } return onAssembly(new FluxDoFinally<>(this, onFinally)); } /** * Map this {@link Flux} into {@link reactor.util.function.Tuple2 Tuple2<Long, T>} * of timemillis and source data. The timemillis corresponds to the elapsed time * between each signal as measured by the {@link Schedulers#parallel() parallel} scheduler. * First duration is measured between the subscription and the first element. * *

* * * @return a new {@link Flux} that emits a tuple of time elapsed in milliseconds and matching data */ public final Flux> elapsed() { return elapsed(Schedulers.parallel()); } /** * Map this {@link Flux} into {@link reactor.util.function.Tuple2 Tuple2<Long, T>} * of timemillis and source data. The timemillis corresponds to the elapsed time * between each signal as measured by the provided {@link Scheduler}. * First duration is measured between the subscription and the first element. *

* * * @param scheduler a {@link Scheduler} instance to {@link Scheduler#now(TimeUnit) read time from} * * @return a new {@link Flux} that emits tuples of time elapsed in milliseconds and matching data */ public final Flux> elapsed(Scheduler scheduler) { Objects.requireNonNull(scheduler, "scheduler"); return onAssembly(new FluxElapsed<>(this, scheduler)); } /** * Emit only the element at the given index position or {@link IndexOutOfBoundsException} * if the sequence is shorter. * *

* * * @param index zero-based index of the only item to emit * * @return a {@link Mono} of the item at the specified zero-based index */ public final Mono elementAt(int index) { return Mono.onAssembly(new MonoElementAt<>(this, index)); } /** * Emit only the element at the given index position or fall back to a * default value if the sequence is shorter. * *

* * * @param index zero-based index of the only item to emit * @param defaultValue a default value to emit if the sequence is shorter * * @return a {@link Mono} of the item at the specified zero-based index or a default value */ public final Mono elementAt(int index, T defaultValue) { return Mono.onAssembly(new MonoElementAt<>(this, index, defaultValue)); } /** * Recursively expand elements into a graph and emit all the resulting element, * in a depth-first traversal order. *

* That is: emit one value from this {@link Flux}, expand it and emit the first value * at this first level of recursion, and so on... When no more recursion is possible, * backtrack to the previous level and re-apply the strategy. *

* For example, given the hierarchical structure *

	 *  A
	 *   - AA
	 *     - aa1
	 *  B
	 *   - BB
	 *     - bb1
	 * 
* * Expands {@code Flux.just(A, B)} into *
	 *  A
	 *  AA
	 *  aa1
	 *  B
	 *  BB
	 *  bb1
	 * 
* * @param expander the {@link Function} applied at each level of recursion to expand * values into a {@link Publisher}, producing a graph. * @param capacityHint a capacity hint to prepare the inner queues to accommodate n * elements per level of recursion. * * @return a {@link Flux} expanded depth-first */ public final Flux expandDeep(Function> expander, int capacityHint) { return onAssembly(new FluxExpand<>(this, expander, false, capacityHint)); } /** * Recursively expand elements into a graph and emit all the resulting element, * in a depth-first traversal order. *

* That is: emit one value from this {@link Flux}, expand it and emit the first value * at this first level of recursion, and so on... When no more recursion is possible, * backtrack to the previous level and re-apply the strategy. *

* For example, given the hierarchical structure *

	 *  A
	 *   - AA
	 *     - aa1
	 *  B
	 *   - BB
	 *     - bb1
	 * 
* * Expands {@code Flux.just(A, B)} into *
	 *  A
	 *  AA
	 *  aa1
	 *  B
	 *  BB
	 *  bb1
	 * 
* * @param expander the {@link Function} applied at each level of recursion to expand * values into a {@link Publisher}, producing a graph. * * @return a {@link Flux} expanded depth-first */ public final Flux expandDeep(Function> expander) { return expandDeep(expander, Queues.SMALL_BUFFER_SIZE); } /** * Recursively expand elements into a graph and emit all the resulting element using * a breadth-first traversal strategy. *

* That is: emit the values from this {@link Flux} first, then expand each at a first level of * recursion and emit all of the resulting values, then expand all of these at a second * level and so on.. *

* For example, given the hierarchical structure *

	 *  A
	 *   - AA
	 *     - aa1
	 *  B
	 *   - BB
	 *     - bb1
	 * 
* * Expands {@code Flux.just(A, B)} into *
	 *  A
	 *  B
	 *  AA
	 *  AB
	 *  aa1
	 *  bb1
	 * 
* * @param expander the {@link Function} applied at each level of recursion to expand * values into a {@link Publisher}, producing a graph. * @param capacityHint a capacity hint to prepare the inner queues to accommodate n * elements per level of recursion. * * @return an breadth-first expanded {@link Flux} */ public final Flux expand(Function> expander, int capacityHint) { return Flux.onAssembly(new FluxExpand<>(this, expander, true, capacityHint)); } /** * Recursively expand elements into a graph and emit all the resulting element using * a breadth-first traversal strategy. *

* That is: emit the values from this {@link Flux} first, then expand each at a first level of * recursion and emit all of the resulting values, then expand all of these at a second * level and so on.. *

* For example, given the hierarchical structure *

	 *  A
	 *   - AA
	 *     - aa1
	 *  B
	 *   - BB
	 *     - bb1
	 * 
* * Expands {@code Flux.just(A, B)} into *
	 *  A
	 *  B
	 *  AA
	 *  AB
	 *  aa1
	 *  bb1
	 * 
* * @param expander the {@link Function} applied at each level of recursion to expand * values into a {@link Publisher}, producing a graph. * * @return an breadth-first expanded {@link Flux} */ public final Flux expand(Function> expander) { return expand(expander, Queues.SMALL_BUFFER_SIZE); } /** * Evaluate each source value against the given {@link Predicate}. If the predicate test succeeds, the value is * emitted. If the predicate test fails, the value is ignored and a request of 1 is made upstream. * *

* * * @param p the {@link Predicate} to test values against * * @return a new {@link Flux} containing only values that pass the predicate test */ public final Flux filter(Predicate p) { if (this instanceof Fuseable) { return onAssembly(new FluxFilterFuseable<>(this, p)); } return onAssembly(new FluxFilter<>(this, p)); } /** * Test each value emitted by this {@link Flux} asynchronously using a generated * {@code Publisher} test. A value is replayed if the first item emitted * by its corresponding test is {@literal true}. It is dropped if its test is either * empty or its first emitted value is {@literal false}. *

* Note that only the first value of the test publisher is considered, and unless it * is a {@link Mono}, test will be cancelled after receiving that first value. Test * publishers are generated and subscribed to in sequence. * * @param asyncPredicate the function generating a {@link Publisher} of {@link Boolean} * for each value, to filter the Flux with * @return a filtered {@link Flux} */ public final Flux filterWhen(Function> asyncPredicate) { return filterWhen(asyncPredicate, Queues.SMALL_BUFFER_SIZE); } /** * Test each value emitted by this {@link Flux} asynchronously using a generated * {@code Publisher} test. A value is replayed if the first item emitted * by its corresponding test is {@literal true}. It is dropped if its test is either * empty or its first emitted value is {@literal false}. *

* Note that only the first value of the test publisher is considered, and unless it * is a {@link Mono}, test will be cancelled after receiving that first value. Test * publishers are generated and subscribed to in sequence. * * @param asyncPredicate the function generating a {@link Publisher} of {@link Boolean} * for each value, to filter the Flux with * @param bufferSize the maximum expected number of values to hold pending a result of * their respective asynchronous predicates, rounded to the next power of two. This is * capped depending on the size of the heap and the JVM limits, so be careful with * large values (although eg. {@literal 65536} should still be fine). Also serves as * the initial request size for the source. * @return a filtered {@link Flux} */ public final Flux filterWhen(Function> asyncPredicate, int bufferSize) { return onAssembly(new FluxFilterWhen<>(this, asyncPredicate, bufferSize)); } /** * Transform the elements emitted by this {@link Flux} asynchronously into Publishers, * then flatten these inner publishers into a single {@link Flux} through merging, * which allow them to interleave. *

* There are three dimensions to this operator that can be compared with * {@link #flatMapSequential(Function) flatMapSequential} and {@link #concatMap(Function) concatMap}: *

    *
  • Generation of inners and subscription: this operator is eagerly * subscribing to its inners.
  • *
  • Ordering of the flattened values: this operator does not necessarily preserve * original ordering, as inner element are flattened as they arrive.
  • *
  • Interleaving: this operator lets values from different inners interleave * (similar to merging the inner sequences).
  • *
*

* *

* @param mapper the {@link Function} to transform input sequence into N sequences {@link Publisher} * @param the merged output sequence type * * @return a new {@link Flux} */ public final Flux flatMap(Function> mapper) { return flatMap(mapper, Queues.SMALL_BUFFER_SIZE, Queues .XS_BUFFER_SIZE); } /** * Transform the elements emitted by this {@link Flux} asynchronously into Publishers, * then flatten these inner publishers into a single {@link Flux} through merging, * which allow them to interleave. *

* There are three dimensions to this operator that can be compared with * {@link #flatMapSequential(Function) flatMapSequential} and {@link #concatMap(Function) concatMap}: *

    *
  • Generation of inners and subscription: this operator is eagerly * subscribing to its inners.
  • *
  • Ordering of the flattened values: this operator does not necessarily preserve * original ordering, as inner element are flattened as they arrive.
  • *
  • Interleaving: this operator lets values from different inners interleave * (similar to merging the inner sequences).
  • *
* The concurrency argument allows to control how many {@link Publisher} can be * subscribed to and merged in parallel. * *

* * * @param mapper the {@link Function} to transform input sequence into N sequences {@link Publisher} * @param concurrency the maximum number of in-flight inner sequences * @param the merged output sequence type * * @return a new {@link Flux} */ public final Flux flatMap(Function> mapper, int concurrency) { return flatMap(mapper, concurrency, Queues.XS_BUFFER_SIZE); } /** * Transform the elements emitted by this {@link Flux} asynchronously into Publishers, * then flatten these inner publishers into a single {@link Flux} through merging, * which allow them to interleave. *

* There are three dimensions to this operator that can be compared with * {@link #flatMapSequential(Function) flatMapSequential} and {@link #concatMap(Function) concatMap}: *

    *
  • Generation of inners and subscription: this operator is eagerly * subscribing to its inners.
  • *
  • Ordering of the flattened values: this operator does not necessarily preserve * original ordering, as inner element are flattened as they arrive.
  • *
  • Interleaving: this operator lets values from different inners interleave * (similar to merging the inner sequences).
  • *
* The concurrency argument allows to control how many {@link Publisher} can be * subscribed to and merged in parallel. The prefetch argument allows to give an * arbitrary prefetch size to the merged {@link Publisher}. * *

* * * @param mapper the {@link Function} to transform input sequence into N sequences {@link Publisher} * @param concurrency the maximum number of in-flight inner sequences * @param prefetch the maximum in-flight elements from each inner {@link Publisher} sequence * @param the merged output sequence type * * @return a merged {@link Flux} */ public final Flux flatMap(Function> mapper, int concurrency, int prefetch) { return flatMap(mapper, false, concurrency, prefetch); } /** * Transform the elements emitted by this {@link Flux} asynchronously into Publishers, * then flatten these inner publishers into a single {@link Flux} through merging, * which allow them to interleave. *

* There are three dimensions to this operator that can be compared with * {@link #flatMapSequential(Function) flatMapSequential} and {@link #concatMap(Function) concatMap}: *

    *
  • Generation of inners and subscription: this operator is eagerly * subscribing to its inners.
  • *
  • Ordering of the flattened values: this operator does not necessarily preserve * original ordering, as inner element are flattened as they arrive.
  • *
  • Interleaving: this operator lets values from different inners interleave * (similar to merging the inner sequences).
  • *
* The concurrency argument allows to control how many {@link Publisher} can be * subscribed to and merged in parallel. The prefetch argument allows to give an * arbitrary prefetch size to the merged {@link Publisher}. This variant will delay * any error until after the rest of the flatMap backlog has been processed. * *

* * * @param mapper the {@link Function} to transform input sequence into N sequences {@link Publisher} * @param concurrency the maximum number of in-flight inner sequences * @param prefetch the maximum in-flight elements from each inner {@link Publisher} sequence * @param the merged output sequence type * * @return a merged {@link Flux} */ public final Flux flatMapDelayError(Function> mapper, int concurrency, int prefetch) { return flatMap(mapper, true, concurrency, prefetch); } /** * Transform the signals emitted by this {@link Flux} asynchronously into Publishers, * then flatten these inner publishers into a single {@link Flux} through merging, * which allow them to interleave. Note that at least one of the signal mappers must * be provided, and all provided mappers must produce a publisher. *

* There are three dimensions to this operator that can be compared with * {@link #flatMapSequential(Function) flatMapSequential} and {@link #concatMap(Function) concatMap}: *

    *
  • Generation of inners and subscription: this operator is eagerly * subscribing to its inners.
  • *
  • Ordering of the flattened values: this operator does not necessarily preserve * original ordering, as inner element are flattened as they arrive.
  • *
  • Interleaving: this operator lets values from different inners interleave * (similar to merging the inner sequences).
  • *
*

* OnError will be transformed into completion signal after its mapping callback has been applied. *

* *

* @param mapperOnNext the {@link Function} to call on next data and returning a sequence to merge. * Use {@literal null} to ignore (provided at least one other mapper is specified). * @param mapperOnError the {@link Function} to call on error signal and returning a sequence to merge. * Use {@literal null} to ignore (provided at least one other mapper is specified). * @param mapperOnComplete the {@link Function} to call on complete signal and returning a sequence to merge. * Use {@literal null} to ignore (provided at least one other mapper is specified). * @param the output {@link Publisher} type target * * @return a new {@link Flux} */ public final Flux flatMap( @Nullable Function> mapperOnNext, @Nullable Function> mapperOnError, @Nullable Supplier> mapperOnComplete) { return onAssembly(new FluxFlatMap<>( new FluxMapSignal<>(this, mapperOnNext, mapperOnError, mapperOnComplete), identityFunction(), false, Queues.XS_BUFFER_SIZE, Queues.xs(), Queues.XS_BUFFER_SIZE, Queues.xs() )); } /** * Transform the items emitted by this {@link Flux} into {@link Iterable}, then flatten the elements from those by * merging them into a single {@link Flux}. * *

* *

* Note that unlike {@link #flatMap(Function)} and {@link #concatMap(Function)}, with Iterable there is * no notion of eager vs lazy inner subscription. The content of the Iterables are all played sequentially. * Thus {@code flatMapIterable} and {@code concatMapIterable} are equivalent offered as a discoverability * improvement for users that explore the API with the concat vs flatMap expectation. * * @param mapper the {@link Function} to transform input sequence into N {@link Iterable} * @param the merged output sequence type * * @return a concatenation of the values from the Iterables obtained from each element in this {@link Flux} */ public final Flux flatMapIterable(Function> mapper) { return flatMapIterable(mapper, Queues.SMALL_BUFFER_SIZE); } /** * Transform the items emitted by this {@link Flux} into {@link Iterable}, then flatten the emissions from those by * merging them into a single {@link Flux}. The prefetch argument allows to give an * arbitrary prefetch size to the merged {@link Iterable}. * *

* *

* Note that unlike {@link #flatMap(Function)} and {@link #concatMap(Function)}, with Iterable there is * no notion of eager vs lazy inner subscription. The content of the Iterables are all played sequentially. * Thus {@code flatMapIterable} and {@code concatMapIterable} are equivalent offered as a discoverability * improvement for users that explore the API with the concat vs flatMap expectation. * * @param mapper the {@link Function} to transform input sequence into N {@link Iterable} * @param prefetch the maximum in-flight elements from each inner {@link Iterable} sequence * @param the merged output sequence type * * @return a concatenation of the values from the Iterables obtained from each element in this {@link Flux} */ public final Flux flatMapIterable(Function> mapper, int prefetch) { return onAssembly(new FluxFlattenIterable<>(this, mapper, prefetch, Queues.get(prefetch))); } /** * Transform the elements emitted by this {@link Flux} asynchronously into Publishers, * then flatten these inner publishers into a single {@link Flux}, but merge them in * the order of their source element. *

* There are three dimensions to this operator that can be compared with * {@link #flatMap(Function) flatMap} and {@link #concatMap(Function) concatMap}: *

    *
  • Generation of inners and subscription: this operator is eagerly * subscribing to its inners (like flatMap).
  • *
  • Ordering of the flattened values: this operator queues elements from * late inners until all elements from earlier inners have been emitted, thus emitting * inner sequences as a whole, in an order that matches their source's order.
  • *
  • Interleaving: this operator does not let values from different inners * interleave (similar looking result to concatMap, but due to queueing of values * that would have been interleaved otherwise).
  • *
* *

* That is to say, whenever a source element is emitted it is transformed to an inner * {@link Publisher}. However, if such an early inner takes more time to complete than * subsequent faster inners, the data from these faster inners will be queued until * the earlier inner completes, so as to maintain source ordering. * *

* * * @param mapper the {@link Function} to transform input sequence into N sequences {@link Publisher} * @param the merged output sequence type * * @return a merged {@link Flux}, subscribing early but keeping the original ordering */ public final Flux flatMapSequential(Function> mapper) { return flatMapSequential(mapper, Queues.SMALL_BUFFER_SIZE); } /** * Transform the elements emitted by this {@link Flux} asynchronously into Publishers, * then flatten these inner publishers into a single {@link Flux}, but merge them in * the order of their source element. *

* There are three dimensions to this operator that can be compared with * {@link #flatMap(Function) flatMap} and {@link #concatMap(Function) concatMap}: *

    *
  • Generation of inners and subscription: this operator is eagerly * subscribing to its inners (like flatMap).
  • *
  • Ordering of the flattened values: this operator queues elements from * late inners until all elements from earlier inners have been emitted, thus emitting * inner sequences as a whole, in an order that matches their source's order.
  • *
  • Interleaving: this operator does not let values from different inners * interleave (similar looking result to concatMap, but due to queueing of values * that would have been interleaved otherwise).
  • *
* *

* That is to say, whenever a source element is emitted it is transformed to an inner * {@link Publisher}. However, if such an early inner takes more time to complete than * subsequent faster inners, the data from these faster inners will be queued until * the earlier inner completes, so as to maintain source ordering. * *

* The concurrency argument allows to control how many merged {@link Publisher} can happen in parallel. * *

* * * @param mapper the {@link Function} to transform input sequence into N sequences {@link Publisher} * @param maxConcurrency the maximum number of in-flight inner sequences * @param the merged output sequence type * * @return a merged {@link Flux}, subscribing early but keeping the original ordering */ public final Flux flatMapSequential(Function> mapper, int maxConcurrency) { return flatMapSequential(mapper, maxConcurrency, Queues.XS_BUFFER_SIZE); } /** * Transform the elements emitted by this {@link Flux} asynchronously into Publishers, * then flatten these inner publishers into a single {@link Flux}, but merge them in * the order of their source element. *

* There are three dimensions to this operator that can be compared with * {@link #flatMap(Function) flatMap} and {@link #concatMap(Function) concatMap}: *

    *
  • Generation of inners and subscription: this operator is eagerly * subscribing to its inners (like flatMap).
  • *
  • Ordering of the flattened values: this operator queues elements from * late inners until all elements from earlier inners have been emitted, thus emitting * inner sequences as a whole, in an order that matches their source's order.
  • *
  • Interleaving: this operator does not let values from different inners * interleave (similar looking result to concatMap, but due to queueing of values * that would have been interleaved otherwise).
  • *
* *

* That is to say, whenever a source element is emitted it is transformed to an inner * {@link Publisher}. However, if such an early inner takes more time to complete than * subsequent faster inners, the data from these faster inners will be queued until * the earlier inner completes, so as to maintain source ordering. * *

* The concurrency argument allows to control how many merged {@link Publisher} * can happen in parallel. The prefetch argument allows to give an arbitrary prefetch * size to the merged {@link Publisher}. * *

* * * @param mapper the {@link Function} to transform input sequence into N sequences {@link Publisher} * @param maxConcurrency the maximum number of in-flight inner sequences * @param prefetch the maximum in-flight elements from each inner {@link Publisher} sequence * @param the merged output sequence type * * @return a merged {@link Flux}, subscribing early but keeping the original ordering */ public final Flux flatMapSequential(Function> mapper, int maxConcurrency, int prefetch) { return flatMapSequential(mapper, false, maxConcurrency, prefetch); } /** * Transform the elements emitted by this {@link Flux} asynchronously into Publishers, * then flatten these inner publishers into a single {@link Flux}, but merge them in * the order of their source element. *

* There are three dimensions to this operator that can be compared with * {@link #flatMap(Function) flatMap} and {@link #concatMap(Function) concatMap}: *

    *
  • Generation of inners and subscription: this operator is eagerly * subscribing to its inners (like flatMap).
  • *
  • Ordering of the flattened values: this operator queues elements from * late inners until all elements from earlier inners have been emitted, thus emitting * inner sequences as a whole, in an order that matches their source's order.
  • *
  • Interleaving: this operator does not let values from different inners * interleave (similar looking result to concatMap, but due to queueing of values * that would have been interleaved otherwise).
  • *
* *

* That is to say, whenever a source element is emitted it is transformed to an inner * {@link Publisher}. However, if such an early inner takes more time to complete than * subsequent faster inners, the data from these faster inners will be queued until * the earlier inner completes, so as to maintain source ordering. * *

* The concurrency argument allows to control how many merged {@link Publisher} * can happen in parallel. The prefetch argument allows to give an arbitrary prefetch * size to the merged {@link Publisher}. This variant will delay any error until after the * rest of the flatMap backlog has been processed. * *

* * * @param mapper the {@link Function} to transform input sequence into N sequences {@link Publisher} * @param maxConcurrency the maximum number of in-flight inner sequences * @param prefetch the maximum in-flight elements from each inner {@link Publisher} sequence * @param the merged output sequence type * * @return a merged {@link Flux}, subscribing early but keeping the original ordering */ public final Flux flatMapSequentialDelayError(Function> mapper, int maxConcurrency, int prefetch) { return flatMapSequential(mapper, true, maxConcurrency, prefetch); } /** * The prefetch configuration of the {@link Flux} * @return the prefetch configuration of the {@link Flux}, -1 if unspecified */ public int getPrefetch() { return -1; } /** * Divide this sequence into dynamically created {@link Flux} (or groups) for each * unique key, as produced by the provided keyMapper {@link Function}. Note that * groupBy works best with a low cardinality of groups, so chose your keyMapper * function accordingly. * *

* * *

* The groups need to be drained and consumed downstream for groupBy to work correctly. * Notably when the criteria produces a large amount of groups, it can lead to hanging * if the groups are not suitably consumed downstream (eg. due to a {@code flatMap} * with a {@code maxConcurrency} parameter that is set too low). * * @param keyMapper the key mapping {@link Function} that evaluates an incoming data and returns a key. * @param the key type extracted from each value of this sequence * * @return a {@link Flux} of {@link GroupedFlux} grouped sequences */ public final Flux> groupBy(Function keyMapper) { return groupBy(keyMapper, identityFunction()); } /** * Divide this sequence into dynamically created {@link Flux} (or groups) for each * unique key, as produced by the provided keyMapper {@link Function}. Note that * groupBy works best with a low cardinality of groups, so chose your keyMapper * function accordingly. * *

* * *

* The groups need to be drained and consumed downstream for groupBy to work correctly. * Notably when the criteria produces a large amount of groups, it can lead to hanging * if the groups are not suitably consumed downstream (eg. due to a {@code flatMap} * with a {@code maxConcurrency} parameter that is set too low). * * @param keyMapper the key mapping {@link Function} that evaluates an incoming data and returns a key. * @param prefetch the number of values to prefetch from the source * @param the key type extracted from each value of this sequence * * @return a {@link Flux} of {@link GroupedFlux} grouped sequences */ public final Flux> groupBy(Function keyMapper, int prefetch) { return groupBy(keyMapper, identityFunction(), prefetch); } /** * Divide this sequence into dynamically created {@link Flux} (or groups) for each * unique key, as produced by the provided keyMapper {@link Function}. Source elements * are also mapped to a different value using the {@code valueMapper}. Note that * groupBy works best with a low cardinality of groups, so chose your keyMapper * function accordingly. * *

* * *

* The groups need to be drained and consumed downstream for groupBy to work correctly. * Notably when the criteria produces a large amount of groups, it can lead to hanging * if the groups are not suitably consumed downstream (eg. due to a {@code flatMap} * with a {@code maxConcurrency} parameter that is set too low). * * @param keyMapper the key mapping function that evaluates an incoming data and returns a key. * @param valueMapper the value mapping function that evaluates which data to extract for re-routing. * @param the key type extracted from each value of this sequence * @param the value type extracted from each value of this sequence * * @return a {@link Flux} of {@link GroupedFlux} grouped sequences * */ public final Flux> groupBy(Function keyMapper, Function valueMapper) { return groupBy(keyMapper, valueMapper, Queues.SMALL_BUFFER_SIZE); } /** * Divide this sequence into dynamically created {@link Flux} (or groups) for each * unique key, as produced by the provided keyMapper {@link Function}. Source elements * are also mapped to a different value using the {@code valueMapper}. Note that * groupBy works best with a low cardinality of groups, so chose your keyMapper * function accordingly. * *

* * *

* The groups need to be drained and consumed downstream for groupBy to work correctly. * Notably when the criteria produces a large amount of groups, it can lead to hanging * if the groups are not suitably consumed downstream (eg. due to a {@code flatMap} * with a {@code maxConcurrency} parameter that is set too low). * * @param keyMapper the key mapping function that evaluates an incoming data and returns a key. * @param valueMapper the value mapping function that evaluates which data to extract for re-routing. * @param prefetch the number of values to prefetch from the source * * @param the key type extracted from each value of this sequence * @param the value type extracted from each value of this sequence * * @return a {@link Flux} of {@link GroupedFlux} grouped sequences * */ public final Flux> groupBy(Function keyMapper, Function valueMapper, int prefetch) { return onAssembly(new FluxGroupBy<>(this, keyMapper, valueMapper, Queues.unbounded(prefetch), Queues.unbounded(prefetch), prefetch)); } /** * Map values from two Publishers into time windows and emit combination of values * in case their windows overlap. The emitted elements are obtained by passing the * value from this {@link Flux} and a {@link Flux} emitting the value from the other * {@link Publisher} to a {@link BiFunction}. *

* There are no guarantees in what order the items get combined when multiple items from * one or both source Publishers overlap. *

* Unlike {@link Flux#join}, items from the second {@link Publisher} will be provided * as a {@link Flux} to the {@code resultSelector}. * *

* * * @param other the other {@link Publisher} to correlate items with * @param leftEnd a function that returns a Publisher whose emissions indicate the * time window for the source value to be considered * @param rightEnd a function that returns a Publisher whose emissions indicate the * time window for the {@code right} Publisher value to be considered * @param resultSelector a function that takes an item emitted by this {@link Flux} and * a {@link Flux} representation of the overlapping item from the other {@link Publisher} * and returns the value to be emitted by the resulting {@link Flux} * @param the type of the elements from the right {@link Publisher} * @param the type for this {@link Flux} window signals * @param the type for the right {@link Publisher} window signals * @param the combined result type * * @return a joining {@link Flux} * @see #join(Publisher, Function, Function, BiFunction) */ public final Flux groupJoin( Publisher other, Function> leftEnd, Function> rightEnd, BiFunction, ? extends R> resultSelector ) { return onAssembly(new FluxGroupJoin( this, other, leftEnd, rightEnd, resultSelector, Queues.unbounded(Queues.XS_BUFFER_SIZE), Queues.unbounded(Queues.XS_BUFFER_SIZE))); } /** * Handle the items emitted by this {@link Flux} by calling a biconsumer with the * output sink for each onNext. At most one {@link SynchronousSink#next(Object)} * call must be performed and/or 0 or 1 {@link SynchronousSink#error(Throwable)} or * {@link SynchronousSink#complete()}. * * @param handler the handling {@link BiConsumer} * @param the transformed type * * @return a transformed {@link Flux} */ public final Flux handle(BiConsumer> handler) { if (this instanceof Fuseable) { return onAssembly(new FluxHandleFuseable<>(this, handler)); } return onAssembly(new FluxHandle<>(this, handler)); } /** * Emit a single boolean true if any of the elements of this {@link Flux} sequence is * equal to the provided value. *

* The implementation uses short-circuit logic and completes with true if * an element matches the value. * *

* * * @param value constant compared to incoming signals * * @return a new {@link Flux} with true if any element is equal to a given value and false * otherwise * */ public final Mono hasElement(T value) { Objects.requireNonNull(value, "value"); return any(t -> Objects.equals(value, t)); } /** * Emit a single boolean true if this {@link Flux} sequence has at least one element. *

* The implementation uses short-circuit logic and completes with true on onNext. * *

* * * @return a new {@link Mono} with true if any value is emitted and false * otherwise */ public final Mono hasElements() { return Mono.onAssembly(new MonoHasElements<>(this)); } /** * Hides the identities of this {@link Flux} instance. *

The main purpose of this operator is to prevent certain identity-based * optimizations from happening, mostly for diagnostic purposes. * * @return a new {@link Flux} preventing {@link Publisher} / {@link Subscription} based Reactor optimizations */ public final Flux hide() { return new FluxHide<>(this); } /** * Ignores onNext signals (dropping them) and only propagate termination events. * *

* *

* * @return a new empty {@link Mono} representing the completion of this {@link Flux}. */ public final Mono ignoreElements() { return Mono.onAssembly(new MonoIgnoreElements<>(this)); } /** * Map values from two Publishers into time windows and emit combination of values * in case their windows overlap. The emitted elements are obtained by passing the * values from this {@link Flux} and the other {@link Publisher} to a {@link BiFunction}. *

* There are no guarantees in what order the items get combined when multiple items from * one or both source Publishers overlap. * *

* * * * @param other the other {@link Publisher} to correlate items with * @param leftEnd a function that returns a Publisher whose emissions indicate the * time window for the source value to be considered * @param rightEnd a function that returns a Publisher whose emissions indicate the * time window for the {@code right} Publisher value to be considered * @param resultSelector a function that takes an item emitted by each Publisher and returns the * value to be emitted by the resulting {@link Flux} * @param the type of the elements from the right {@link Publisher} * @param the type for this {@link Flux} window signals * @param the type for the right {@link Publisher} window signals * @param the combined result type * * @return a joining {@link Flux} * @see #groupJoin(Publisher, Function, Function, BiFunction) */ public final Flux join( Publisher other, Function> leftEnd, Function> rightEnd, BiFunction resultSelector ) { return onAssembly(new FluxJoin( this, other, leftEnd, rightEnd, resultSelector, Queues .unbounded(Queues.XS_BUFFER_SIZE))); } /** * Emit the last element observed before complete signal as a {@link Mono}, or emit * {@link NoSuchElementException} error if the source was empty. * For a passive version use {@link #takeLast(int)} * *

* * * @return a {@link Mono} with the last value in this {@link Flux} */ public final Mono last() { if (this instanceof Callable) { @SuppressWarnings("unchecked") Callable thiz = (Callable)this; return convertToMono(thiz); } return Mono.onAssembly(new MonoTakeLastOne<>(this)); } /** * Emit the last element observed before complete signal as a {@link Mono}, or emit * the {@code defaultValue} if the source was empty. * For a passive version use {@link #takeLast(int)} * *

* * @param defaultValue a single fallback item if this {@link Flux} is empty * @return a {@link Mono} with the last value in this {@link Flux} */ public final Mono last(T defaultValue) { if (this instanceof Callable) { @SuppressWarnings("unchecked") Callable thiz = (Callable)this; if(thiz instanceof Fuseable.ScalarCallable){ @SuppressWarnings("unchecked") Fuseable.ScalarCallable c = (Fuseable.ScalarCallable)thiz; T v; try { v = c.call(); } catch (Exception e) { return Mono.error(e); } if(v == null){ return Mono.just(defaultValue); } return Mono.just(v); } Mono.onAssembly(new MonoCallable<>(thiz)); } return Mono.onAssembly(new MonoTakeLastOne<>(this, defaultValue)); } /** * Ensure that backpressure signals from downstream subscribers are split into batches * capped at the provided {@code prefetchRate} when propagated upstream, effectively * rate limiting the upstream {@link Publisher}. *

* Typically used for scenarios where consumer(s) request a large amount of data * (eg. {@code Long.MAX_VALUE}) but the data source behaves better or can be optimized * with smaller requests (eg. database paging, etc...). All data is still processed, * unlike with {@link #limitRequest(long)} which will cap the grand total request * amount. *

* Equivalent to {@code flux.publishOn(Schedulers.immediate(), prefetchRate).subscribe() } * * @param prefetchRate the limit to apply to downstream's backpressure * * @return a {@link Flux} limiting downstream's backpressure * @see #publishOn(Scheduler, int) * @see #limitRequest(long) */ public final Flux limitRate(int prefetchRate) { return onAssembly(this.publishOn(Schedulers.immediate(), prefetchRate)); } /** * Ensure that backpressure signals from downstream subscribers are split into batches * capped at the provided {@code highTide} first, then replenishing at the provided * {@code lowTide}, effectively rate limiting the upstream {@link Publisher}. *

* Typically used for scenarios where consumer(s) request a large amount of data * (eg. {@code Long.MAX_VALUE}) but the data source behaves better or can be optimized * with smaller requests (eg. database paging, etc...). All data is still processed, * unlike with {@link #limitRequest(long)} which will cap the grand total request * amount. *

* Similar to {@code flux.publishOn(Schedulers.immediate(), prefetchRate).subscribe() }, * except with a customized "low tide" instead of the default 75%. * Note that the smaller the lowTide is, the higher the potential for concurrency * between request and data production. And thus the more extraneous replenishment * requests this operator could make. For example, for a global downstream * request of 14, with a highTide of 10 and a lowTide of 2, the operator would perform * 7 low tide requests, whereas with the default lowTide of 8 it would only perform one. * * @param highTide the initial request amount * @param lowTide the subsequent (or replenishing) request amount * * @return a {@link Flux} limiting downstream's backpressure and customizing the * replenishment request amount * @see #publishOn(Scheduler, int) * @see #limitRequest(long) */ public final Flux limitRate(int highTide, int lowTide) { return onAssembly(this.publishOn(Schedulers.immediate(), true, highTide, lowTide)); } /** * Ensure that the total amount requested upstream is capped at {@code cap}. * Backpressure signals from downstream subscribers are smaller than the cap are * propagated as is, but if they would cause the total requested amount to go over the * cap, they are reduced to the minimum value that doesn't go over. *

* As a result, this operator never let the upstream produce more elements than the * cap, and it can be used as a stricter form of {@link #take(long)}. Typically useful * for cases where a race between request and cancellation can lead the upstream to * producing a lot of extraneous data, and such a production is undesirable (e.g. * a source that would send the extraneous data over the network). * * @param requestCap the global backpressure limit to apply to the sum of downstream's requests * * @return a {@link Flux} that requests AT MOST {@code cap} from upstream in total. * @see #limitRate(int) * @see #take(long) */ public final Flux limitRequest(long requestCap) { return onAssembly(new FluxLimitRequest<>(this, requestCap)); } /** * Observe all Reactive Streams signals and trace them using {@link Logger} support. * Default will use {@link Level#INFO} and {@code java.util.logging}. * If SLF4J is available, it will be used instead. *

* *

* The default log category will be "reactor.Flux.", followed by a suffix generated from * the source operator, e.g. "reactor.Flux.Map". * * @return a new {@link Flux} that logs signals */ public final Flux log() { return log(null, Level.INFO); } /** * Observe all Reactive Streams signals and trace them using {@link Logger} support. * Default will use {@link Level#INFO} and {@code java.util.logging}. * If SLF4J is available, it will be used instead. *

* *

* @param category to be mapped into logger configuration (e.g. org.springframework * .reactor). If category ends with "." like "reactor.", a generated operator * suffix will be added, e.g. "reactor.Flux.Map". * * @return a new {@link Flux} that logs signals */ public final Flux log(String category) { return log(category, Level.INFO); } /** * Observe Reactive Streams signals matching the passed filter {@code options} and * trace them using {@link Logger} support. Default will use {@link Level#INFO} and * {@code java.util.logging}. If SLF4J is available, it will be used instead. *

* Options allow fine grained filtering of the traced signal, for instance to only * capture onNext and onError: *

	 *     flux.log("category", Level.INFO, SignalType.ON_NEXT, SignalType.ON_ERROR)
	 * 

* *

* @param category to be mapped into logger configuration (e.g. org.springframework * .reactor). If category ends with "." like "reactor.", a generated operator * suffix will be added, e.g. "reactor.Flux.Map". * @param level the {@link Level} to enforce for this tracing Flux (only FINEST, FINE, * INFO, WARNING and SEVERE are taken into account) * @param options a vararg {@link SignalType} option to filter log messages * * @return a new {@link Flux} that logs signals */ public final Flux log(@Nullable String category, Level level, SignalType... options) { return log(category, level, false, options); } /** * Observe Reactive Streams signals matching the passed filter {@code options} and * trace them using {@link Logger} support. Default will use {@link Level#INFO} and * {@code java.util.logging}. If SLF4J is available, it will be used instead. *

* Options allow fine grained filtering of the traced signal, for instance to only * capture onNext and onError: *

	 *     flux.log("category", Level.INFO, SignalType.ON_NEXT, SignalType.ON_ERROR)
	 *
	 * 
	 *
	 * @param category to be mapped into logger configuration (e.g. org.springframework
	 * .reactor). If category ends with "." like "reactor.", a generated operator
	 * suffix will be added, e.g. "reactor.Flux.Map".
	 * @param level the {@link Level} to enforce for this tracing Flux (only FINEST, FINE,
	 * INFO, WARNING and SEVERE are taken into account)
	 * @param showOperatorLine capture the current stack to display operator class/line number.
	 * @param options a vararg {@link SignalType} option to filter log messages
	 *
	 * @return a new {@link Flux} that logs signals
	 */
	public final Flux log(@Nullable String category,
			Level level,
			boolean showOperatorLine,
			SignalType... options) {
		SignalLogger log = new SignalLogger<>(this, category, level,
				showOperatorLine, options);

		if (this instanceof Fuseable) {
			return onAssembly(new FluxLogFuseable<>(this, log));
		}
		return onAssembly(new FluxLog<>(this, log));
	}

	/**
	 * Transform the items emitted by this {@link Flux} by applying a synchronous function
	 * to each item.
	 * 

* *

* @param mapper the synchronous transforming {@link Function} * @param the transformed type * * @return a transformed {@link Flux} */ public final Flux map(Function mapper) { if (this instanceof Fuseable) { return onAssembly(new FluxMapFuseable<>(this, mapper)); } return onAssembly(new FluxMap<>(this, mapper)); } /** * Transform incoming onNext, onError and onComplete signals into {@link Signal} instances, * materializing these signals. * Since the error is materialized as a {@code Signal}, the propagation will be stopped and onComplete will be * emitted. Complete signal will first emit a {@code Signal.complete()} and then effectively complete the flux. * *

* * * @return a {@link Flux} of materialized {@link Signal} * @see #dematerialize() */ public final Flux> materialize() { return onAssembly(new FluxMaterialize<>(this)); } /** * Merge data from this {@link Flux} and a {@link Publisher} into an interleaved merged * sequence. Unlike {@link #concatWith(Publisher) concat}, inner sources are subscribed * to eagerly. *

* *

* Note that merge is tailored to work with asynchronous sources or finite sources. When dealing with * an infinite source that doesn't already publish on a dedicated Scheduler, you must isolate that source * in its own Scheduler, as merge would otherwise attempt to drain it before subscribing to * another source. * * @param other the {@link Publisher} to merge with * * @return a new {@link Flux} */ public final Flux mergeWith(Publisher other) { if (this instanceof FluxMerge) { FluxMerge fluxMerge = (FluxMerge) this; return fluxMerge.mergeAdditionalSource(other, Queues::get); } return merge(this, other); } /** * Give a name to this sequence, which can be retrieved using {@link Scannable#name()} * as long as this is the first reachable {@link Scannable#parents()}. * * @param name a name for the sequence * @return the same sequence, but bearing a name */ public final Flux name(String name) { return FluxName.createOrAppend(this, name); } /** * Emit only the first item emitted by this {@link Flux}, into a new {@link Mono}. *

* *

* * @return a new {@link Mono} emitting the first value in this {@link Flux} */ public final Mono next() { if(this instanceof Callable){ @SuppressWarnings("unchecked") Callable m = (Callable)this; return convertToMono(m); } return Mono.onAssembly(new MonoNext<>(this)); } /** * Evaluate each accepted value against the given {@link Class} type. If the * a value matches the type, it is passed into the resulting {@link Flux}. Otherwise * the value is ignored and a request of 1 is emitted. * *

* * * @param clazz the {@link Class} type to test values against * * @return a new {@link Flux} filtered on items of the requested type */ public final Flux ofType(final Class clazz) { Objects.requireNonNull(clazz, "clazz"); return filter(o -> clazz.isAssignableFrom(o.getClass())).cast(clazz); } /** * Request an unbounded demand and push to the returned {@link Flux}, or park the * observed elements if not enough demand is requested downstream. Errors will be * delayed until the buffer gets consumed. * *

* * * @return a backpressured {@link Flux} that buffers with unbounded capacity * */ public final Flux onBackpressureBuffer() { return onAssembly(new FluxOnBackpressureBuffer<>(this, Queues .SMALL_BUFFER_SIZE, true, null)); } /** * Request an unbounded demand and push to the returned {@link Flux}, or park the * observed elements if not enough demand is requested downstream. Errors will be * immediately emitted on overflow regardless of the pending buffer. * *

* * * @param maxSize maximum buffer backlog size before immediate error * * @return a backpressured {@link Flux} that buffers with bounded capacity * */ public final Flux onBackpressureBuffer(int maxSize) { return onAssembly(new FluxOnBackpressureBuffer<>(this, maxSize, false, null)); } /** * Request an unbounded demand and push to the returned {@link Flux}, or park the * observed elements if not enough demand is requested downstream. Overflow error * will be delayed after the current backlog is consumed. However the * {@link Consumer} will be immediately invoked. * *

* * * @param maxSize maximum buffer backlog size before overflow callback is called * @param onOverflow callback to invoke on overflow * * @return a backpressured {@link Flux} that buffers with a bounded capacity * */ public final Flux onBackpressureBuffer(int maxSize, Consumer onOverflow) { Objects.requireNonNull(onOverflow, "onOverflow"); return onAssembly(new FluxOnBackpressureBuffer<>(this, maxSize, false, onOverflow)); } /** * Request an unbounded demand and push to the returned {@link Flux}, or park the observed * elements if not enough demand is requested downstream, within a {@code maxSize} * limit. Over that limit, the overflow strategy is applied (see {@link BufferOverflowStrategy}). *

* Note that for the {@link BufferOverflowStrategy#ERROR ERROR} strategy, the overflow * error will be delayed after the current backlog is consumed. * *

* * * @param maxSize maximum buffer backlog size before overflow strategy is applied * @param bufferOverflowStrategy strategy to apply to overflowing elements * * @return a backpressured {@link Flux} that buffers up to a capacity then applies an * overflow strategy */ public final Flux onBackpressureBuffer(int maxSize, BufferOverflowStrategy bufferOverflowStrategy) { Objects.requireNonNull(bufferOverflowStrategy, "bufferOverflowStrategy"); return onAssembly(new FluxOnBackpressureBufferStrategy<>(this, maxSize, null, bufferOverflowStrategy)); } /** * Request an unbounded demand and push to the returned {@link Flux}, or park the observed * elements if not enough demand is requested downstream, within a {@code maxSize} * limit. Over that limit, the overflow strategy is applied (see {@link BufferOverflowStrategy}). *

* A {@link Consumer} is immediately invoked when there is an overflow, receiving the * value that was discarded because of the overflow (which can be different from the * latest element emitted by the source in case of a * {@link BufferOverflowStrategy#DROP_LATEST DROP_LATEST} strategy). * *

* Note that for the {@link BufferOverflowStrategy#ERROR ERROR} strategy, the overflow * error will be delayed after the current backlog is consumed. The consumer is still * invoked immediately. * *

* * * @param maxSize maximum buffer backlog size before overflow callback is called * @param onBufferOverflow callback to invoke on overflow * @param bufferOverflowStrategy strategy to apply to overflowing elements * * @return a backpressured {@link Flux} that buffers up to a capacity then applies an * overflow strategy */ public final Flux onBackpressureBuffer(int maxSize, Consumer onBufferOverflow, BufferOverflowStrategy bufferOverflowStrategy) { Objects.requireNonNull(onBufferOverflow, "onBufferOverflow"); Objects.requireNonNull(bufferOverflowStrategy, "bufferOverflowStrategy"); return onAssembly(new FluxOnBackpressureBufferStrategy<>(this, maxSize, onBufferOverflow, bufferOverflowStrategy)); } /** * Request an unbounded demand and push to the returned {@link Flux}, or park the observed * elements if not enough demand is requested downstream, within a {@code maxSize} * limit and for a maximum {@link Duration} of {@code ttl} (as measured on the * {@link Schedulers#elastic() elastic Scheduler}). Over that limit, oldest * elements from the source are dropped. *

* Elements evicted based on the TTL are passed to a cleanup {@link Consumer}, which * is also immediately invoked when there is an overflow. * *

* * * @param ttl maximum {@link Duration} for which an element is kept in the backlog * @param maxSize maximum buffer backlog size before overflow callback is called * @param onBufferEviction callback to invoke once TTL is reached or on overflow * * @return a backpressured {@link Flux} that buffers with a TTL and up to a capacity then applies an * overflow strategy */ public final Flux onBackpressureBuffer(Duration ttl, int maxSize, Consumer onBufferEviction) { return onBackpressureBuffer(ttl, maxSize, onBufferEviction, Schedulers.parallel()); } /** * Request an unbounded demand and push to the returned {@link Flux}, or park the observed * elements if not enough demand is requested downstream, within a {@code maxSize} * limit and for a maximum {@link Duration} of {@code ttl} (as measured on the provided * {@link Scheduler}). Over that limit, oldest elements from the source are dropped. *

* Elements evicted based on the TTL are passed to a cleanup {@link Consumer}, which * is also immediately invoked when there is an overflow. * *

* * * @param ttl maximum {@link Duration} for which an element is kept in the backlog * @param maxSize maximum buffer backlog size before overflow callback is called * @param onBufferEviction callback to invoke once TTL is reached or on overflow * @param scheduler the scheduler on which to run the timeout check * * @return a backpressured {@link Flux} that buffers with a TTL and up to a capacity then applies an * overflow strategy */ public final Flux onBackpressureBuffer(Duration ttl, int maxSize, Consumer onBufferEviction, Scheduler scheduler) { Objects.requireNonNull(ttl, "ttl"); Objects.requireNonNull(onBufferEviction, "onBufferEviction"); return onAssembly(new FluxOnBackpressureBufferTimeout<>(this, ttl, scheduler, maxSize, onBufferEviction)); } /** * Request an unbounded demand and push to the returned {@link Flux}, or drop * the observed elements if not enough demand is requested downstream. * *

* * * @return a backpressured {@link Flux} that drops overflowing elements */ public final Flux onBackpressureDrop() { return onAssembly(new FluxOnBackpressureDrop<>(this)); } /** * Request an unbounded demand and push to the returned {@link Flux}, or drop and * notify dropping {@link Consumer} with the observed elements if not enough demand * is requested downstream. * *

* * * @param onDropped the Consumer called when an value gets dropped due to lack of downstream requests * @return a backpressured {@link Flux} that drops overflowing elements */ public final Flux onBackpressureDrop(Consumer onDropped) { return onAssembly(new FluxOnBackpressureDrop<>(this, onDropped)); } /** * Request an unbounded demand and push to the returned {@link Flux}, or emit onError * fom {@link Exceptions#failWithOverflow} if not enough demand is requested * downstream. * *

* * * @return a backpressured {@link Flux} that errors on overflowing elements */ public final Flux onBackpressureError() { return onBackpressureDrop(t -> { throw Exceptions.failWithOverflow();}); } /** * Request an unbounded demand and push to the returned {@link Flux}, or only keep * the most recent observed item if not enough demand is requested downstream. * *

* * * @return a backpressured {@link Flux} that will only keep a reference to the last observed item */ public final Flux onBackpressureLatest() { return onAssembly(new FluxOnBackpressureLatest<>(this)); } /** * Transform any error emitted by this {@link Flux} by synchronously applying a function to it. *

* *

* * @param mapper the error transforming {@link Function} * * @return a {@link Flux} that transforms source errors to other errors */ public final Flux onErrorMap(Function mapper) { return onErrorResume(e -> Mono.error(mapper.apply(e))); } /** * Transform an error emitted by this {@link Flux} by synchronously applying a function * to it if the error matches the given type. Otherwise let the error pass through. *

* *

* @param type the class of the exception type to react to * @param mapper the error transforming {@link Function} * @param the error type * * @return a {@link Flux} that transforms some source errors to other errors */ public final Flux onErrorMap(Class type, Function mapper) { @SuppressWarnings("unchecked") Function handler = (Function)mapper; return onErrorMap(type::isInstance, handler); } /** * Transform an error emitted by this {@link Flux} by synchronously applying a function * to it if the error matches the given predicate. Otherwise let the error pass through. *

* * * @param predicate the error predicate * @param mapper the error transforming {@link Function} * * @return a {@link Flux} that transforms some source errors to other errors */ public final Flux onErrorMap(Predicate predicate, Function mapper) { return onErrorResume(predicate, e -> Mono.error(mapper.apply(e))); } /** * Subscribe to a returned fallback publisher when any error occurs, using a function to * choose the fallback depending on the error. * *

* *

* @param fallback the function to choose the fallback to an alternative {@link Publisher} * * @return a {@link Flux} falling back upon source onError */ public final Flux onErrorResume(Function> fallback) { return onAssembly(new FluxOnErrorResume<>(this, fallback)); } /** * Subscribe to a fallback publisher when an error matching the given type * occurs, using a function to choose the fallback depending on the error. *

* * * @param type the error type to match * @param fallback the function to choose the fallback to an alternative {@link Publisher} * @param the error type * * @return a {@link Flux} falling back upon source onError */ public final Flux onErrorResume(Class type, Function> fallback) { Objects.requireNonNull(type, "type"); @SuppressWarnings("unchecked") Function> handler = (Function>)fallback; return onErrorResume(type::isInstance, handler); } /** * Subscribe to a fallback publisher when an error matching a given predicate * occurs. *

* * * @param predicate the error predicate to match * @param fallback the function to choose the fallback to an alternative {@link Publisher} * * @return a {@link Flux} falling back upon source onError */ public final Flux onErrorResume(Predicate predicate, Function> fallback) { Objects.requireNonNull(predicate, "predicate"); return onErrorResume(e -> predicate.test(e) ? fallback.apply(e) : error(e)); } /** * Simply emit a captured fallback value when any error is observed on this {@link Flux}. *

* *

* @param fallbackValue the value to emit if an error occurs * * @return a new falling back {@link Flux} */ public final Flux onErrorReturn(T fallbackValue) { return onErrorResume(t -> just(fallbackValue)); } /** * Simply emit a captured fallback value when an error of the specified type is * observed on this {@link Flux}. *

* * @param type the error type to match * @param fallbackValue the value to emit if an error occurs that matches the type * @param the error type * * @return a new falling back {@link Flux} */ public final Flux onErrorReturn(Class type, T fallbackValue) { return onErrorResume(type, t -> just(fallbackValue)); } /** * Simply emit a captured fallback value when an error matching the given predicate is * observed on this {@link Flux}. *

* * @param predicate the error predicate to match * @param fallbackValue the value to emit if an error occurs that matches the predicate * * @return a new falling back {@link Flux} */ public final Flux onErrorReturn(Predicate predicate, T fallbackValue) { return onErrorResume(predicate, t -> just(fallbackValue)); } /** * Detaches both the child {@link Subscriber} and the {@link Subscription} on * termination or cancellation. *

This is an advanced interoperability operator that should help with odd * retention scenarios when running with non-reactor {@link Subscriber}. * * @return a detachable {@link Flux} */ public final Flux onTerminateDetach() { return new FluxDetach<>(this); } /** * Pick the first {@link Publisher} between this {@link Flux} and another publisher * to emit any signal (onNext/onError/onComplete) and replay all signals from that * {@link Publisher}, effectively behaving like the fastest of these competing sources. * *

* *

* @param other the {@link Publisher} to race with * * @return the fastest sequence * @see #first */ public final Flux or(Publisher other) { if (this instanceof FluxFirstEmitting) { FluxFirstEmitting publisherAmb = (FluxFirstEmitting) this; FluxFirstEmitting result = publisherAmb.ambAdditionalSource(other); if (result != null) { return result; } } return first(this, other); } /** * Prepare this {@link Flux} by dividing data on a number of 'rails' matching the * number of CPU cores, in a round-robin fashion. Note that to actually perform the * work in parallel, you should call {@link ParallelFlux#runOn(Scheduler)} afterward. * *

* * * @return a new {@link ParallelFlux} instance */ public final ParallelFlux parallel() { return parallel(Runtime.getRuntime() .availableProcessors()); } /** * Prepare this {@link Flux} by dividing data on a number of 'rails' matching the * provided {@code parallelism} parameter, in a round-robin fashion. Note that to * actually perform the work in parallel, you should call {@link ParallelFlux#runOn(Scheduler)} * afterward. * *

* * * @param parallelism the number of parallel rails * * @return a new {@link ParallelFlux} instance */ public final ParallelFlux parallel(int parallelism) { return parallel(parallelism, Queues.SMALL_BUFFER_SIZE); } /** * Prepare this {@link Flux} by dividing data on a number of 'rails' matching the * provided {@code parallelism} parameter, in a round-robin fashion and using a * custom prefetch amount and queue for dealing with the source {@link Flux}'s values. * Note that to actually perform the work in parallel, you should call * {@link ParallelFlux#runOn(Scheduler)} afterward. * *

* * * @param parallelism the number of parallel rails * @param prefetch the number of values to prefetch from the source * * @return a new {@link ParallelFlux} instance */ public final ParallelFlux parallel(int parallelism, int prefetch) { return ParallelFlux.from(this, parallelism, prefetch, Queues.get(prefetch)); } /** * Prepare a {@link ConnectableFlux} which shares this {@link Flux} sequence and * dispatches values to subscribers in a backpressure-aware manner. Prefetch will * default to {@link Queues#SMALL_BUFFER_SIZE}. This will effectively turn * any type of sequence into a hot sequence. *

* Backpressure will be coordinated on {@link Subscription#request} and if any * {@link Subscriber} is missing demand (requested = 0), multicast will pause * pushing/pulling. *

* * * @return a new {@link ConnectableFlux} */ public final ConnectableFlux publish() { return publish(Queues.SMALL_BUFFER_SIZE); } /** * Prepare a {@link ConnectableFlux} which shares this {@link Flux} sequence and * dispatches values to subscribers in a backpressure-aware manner. This will * effectively turn any type of sequence into a hot sequence. *

* Backpressure will be coordinated on {@link Subscription#request} and if any * {@link Subscriber} is missing demand (requested = 0), multicast will pause * pushing/pulling. *

* * * @param prefetch bounded requested demand * * @return a new {@link ConnectableFlux} */ public final ConnectableFlux publish(int prefetch) { return onAssembly(new FluxPublish<>(this, prefetch, Queues .get(prefetch))); } /** * Shares a sequence for the duration of a function that may transform it and * consume it as many times as necessary without causing multiple subscriptions * to the upstream. * * @param transform the transformation function * @param the output value type * * @return a new {@link Flux} */ public final Flux publish(Function, ? extends Publisher> transform) { return publish(transform, Queues.SMALL_BUFFER_SIZE); } /** * Shares a sequence for the duration of a function that may transform it and * consume it as many times as necessary without causing multiple subscriptions * to the upstream. * * @param transform the transformation function * @param prefetch the request size * @param the output value type * * @return a new {@link Flux} */ public final Flux publish(Function, ? extends Publisher> transform, int prefetch) { return onAssembly(new FluxPublishMulticast<>(this, transform, prefetch, Queues .get(prefetch))); } /** * Prepare a {@link Mono} which shares this {@link Flux} sequence and dispatches the * first observed item to subscribers in a backpressure-aware manner. * This will effectively turn any type of sequence into a hot sequence when the first * {@link Subscriber} subscribes. *

* * * @return a new {@link Mono} */ public final Mono publishNext() { return Mono.onAssembly(new MonoProcessor<>(this)); } /** * Run onNext, onComplete and onError on a supplied {@link Scheduler} * {@link Worker Worker}. *

* This operator influences the threading context where the rest of the operators in * the chain below it will execute, up to a new occurrence of {@code publishOn}. *

* *

* Typically used for fast publisher, slow consumer(s) scenarios. *

	 * {@code flux.publishOn(Schedulers.single()).subscribe() }
	 * 
* * @param scheduler a {@link Scheduler} providing the {@link Worker} where to publish * * @return a {@link Flux} producing asynchronously on a given {@link Scheduler} */ public final Flux publishOn(Scheduler scheduler) { return publishOn(scheduler, Queues.SMALL_BUFFER_SIZE); } /** * Run onNext, onComplete and onError on a supplied {@link Scheduler} * {@link Worker}. *

* This operator influences the threading context where the rest of the operators in * the chain below it will execute, up to a new occurrence of {@code publishOn}. *

* *

* Typically used for fast publisher, slow consumer(s) scenarios. *

	 * {@code flux.publishOn(Schedulers.single()).subscribe() }
	 * 
* * @param scheduler a {@link Scheduler} providing the {@link Worker} where to publish * @param prefetch the asynchronous boundary capacity * * @return a {@link Flux} producing asynchronously */ public final Flux publishOn(Scheduler scheduler, int prefetch) { return publishOn(scheduler, true, prefetch); } /** * Run onNext, onComplete and onError on a supplied {@link Scheduler} * {@link Worker}. *

* This operator influences the threading context where the rest of the operators in * the chain below it will execute, up to a new occurrence of {@code publishOn}. *

* *

* Typically used for fast publisher, slow consumer(s) scenarios. *

	 * {@code flux.publishOn(Schedulers.single()).subscribe() }
	 * 
* * @param scheduler a {@link Scheduler} providing the {@link Worker} where to publish * @param delayError should the buffer be consumed before forwarding any error * @param prefetch the asynchronous boundary capacity * * @return a {@link Flux} producing asynchronously */ public final Flux publishOn(Scheduler scheduler, boolean delayError, int prefetch) { return publishOn(scheduler, delayError, prefetch, prefetch); } final Flux publishOn(Scheduler scheduler, boolean delayError, int prefetch, int lowTide) { if (this instanceof Callable) { if (this instanceof Fuseable.ScalarCallable) { @SuppressWarnings("unchecked") Fuseable.ScalarCallable s = (Fuseable.ScalarCallable) this; try { return onAssembly(new FluxSubscribeOnValue<>(s.call(), scheduler)); } catch (Exception e) { //leave FluxSubscribeOnCallable defer exception call } } @SuppressWarnings("unchecked") Callable c = (Callable)this; return onAssembly(new FluxSubscribeOnCallable<>(c, scheduler)); } return onAssembly(new FluxPublishOn<>(this, scheduler, delayError, prefetch, lowTide, Queues.get(prefetch))); } /** * Reduce the values from this {@link Flux} sequence into an single object of the same * type than the emitted items. Reduction is performed using a {@link BiFunction} that * takes the intermediate result of the reduction and the current value and returns * the next intermediate value of the reduction. It will ignore sequence with 0 or 1 * elements. * *

* * * @param aggregator the reducing {@link BiFunction} * * @return a reduced {@link Flux} */ public final Mono reduce(BiFunction aggregator) { if (this instanceof Callable){ @SuppressWarnings("unchecked") Callable thiz = (Callable)this; return convertToMono(thiz); } return Mono.onAssembly(new MonoReduce<>(this, aggregator)); } /** * Reduce the values from this {@link Flux} sequence into an single object matching the * type of a seed value. Reduction is performed using a {@link BiFunction} that * takes the intermediate result of the reduction and the current value and returns * the next intermediate value of the reduction. First element is paired with the seed * value, {@literal initial}. * *

* * * @param accumulator the reducing {@link BiFunction} * @param initial a {@link Supplier} of the seed, called on subscription and passed to the the reducing {@link BiFunction} * @param the type of the seed and the reduced object * * @return a reduced {@link Flux} * */ public final Mono reduceWith(Supplier initial, BiFunction accumulator) { return Mono.onAssembly(new MonoReduceSeed<>(this, initial, accumulator)); } /** * Repeatedly and indefinitely subscribe to the source upon completion of the * previous subscription. * *

* * * @return an indefinitely repeated {@link Flux} on onComplete */ public final Flux repeat() { return repeat(ALWAYS_BOOLEAN_SUPPLIER); } /** * Repeatedly subscribe to the source if the predicate returns true after completion of the previous subscription. * *

* * * @param predicate the boolean to evaluate on onComplete. * * @return a {@link Flux} that repeats on onComplete while the predicate matches */ public final Flux repeat(BooleanSupplier predicate) { return onAssembly(new FluxRepeatPredicate<>(this, predicate)); } /** * Repeatedly subscribe to the source {@literal numRepeat} times. * *

* * * @param numRepeat the number of times to re-subscribe on onComplete * * @return a {@link Flux} that repeats on onComplete, up to the specified number of repetitions */ public final Flux repeat(long numRepeat) { if(numRepeat == 0L){ return empty(); } return onAssembly(new FluxRepeat<>(this, numRepeat)); } /** * Repeatedly subscribe to the source if the predicate returns true after completion of the previous * subscription. A specified maximum of repeat will limit the number of re-subscribe. * *

* * * @param numRepeat the number of times to re-subscribe on complete * @param predicate the boolean to evaluate on onComplete * * @return a {@link Flux} that repeats on onComplete while the predicate matches, * up to the specified number of repetitions */ public final Flux repeat(long numRepeat, BooleanSupplier predicate) { return defer( () -> repeat(countingBooleanSupplier(predicate, numRepeat))); } /** * Repeatedly subscribe to this {@link Flux} when a companion sequence emits elements in * response to the flux completion signal. Any terminal signal from the companion * sequence will terminate the resulting {@link Flux} with the same signal immediately. *

If the companion sequence signals when this {@link Flux} is active, the repeat * attempt is suppressed. *

* * * @param repeatFactory the {@link Function} that returns the associated {@link Publisher} * companion, given a {@link Flux} that signals each onComplete as a {@link Long} * representing the number of source elements emitted in the latest attempt. * * @return a {@link Flux} that repeats on onComplete when the companion {@link Publisher} produces an * onNext signal */ public final Flux repeatWhen(Function, ? extends Publisher> repeatFactory) { return onAssembly(new FluxRepeatWhen<>(this, repeatFactory)); } /** * Turn this {@link Flux} into a hot source and cache last emitted signals for further {@link Subscriber}. Will * retain an unbounded amount of onNext signals. Completion and Error will also be * replayed. *

* * * @return a replaying {@link ConnectableFlux} */ public final ConnectableFlux replay() { return replay(Integer.MAX_VALUE); } /** * Turn this {@link Flux} into a connectable hot source and cache last emitted * signals for further {@link Subscriber}. * Will retain up to the given history size onNext signals. Completion and Error will also be * replayed. *

* Note that {@code cache(0)} will only cache the terminal signal without * expiration. * *

* * * @param history number of events retained in history excluding complete and * error * * @return a replaying {@link ConnectableFlux} * */ public final ConnectableFlux replay(int history) { return onAssembly(new FluxReplay<>(this, history, 0L, null)); } /** * Turn this {@link Flux} into a connectable hot source and cache last emitted signals * for further {@link Subscriber}. Will retain each onNext up to the given per-item * expiry timeout. *

* Completion and Error will also be replayed until {@code ttl} triggers in which case * the next {@link Subscriber} will start over a new subscription * *

* * * @param ttl Per-item and post termination timeout duration * * @return a replaying {@link ConnectableFlux} */ public final ConnectableFlux replay(Duration ttl) { return replay(Integer.MAX_VALUE, ttl); } /** * Turn this {@link Flux} into a connectable hot source and cache last emitted signals * for further {@link Subscriber}. Will retain up to the given history size onNext * signals with a per-item ttl. *

* Completion and Error will also be replayed until {@code ttl} triggers in which case * the next {@link Subscriber} will start over a new subscription * *

* * * @param history number of events retained in history excluding complete and error * @param ttl Per-item and post termination timeout duration * * @return a replaying {@link ConnectableFlux} */ public final ConnectableFlux replay(int history, Duration ttl) { return replay(history, ttl, Schedulers.parallel()); } /** * Turn this {@link Flux} into a connectable hot source and cache last emitted signals * for further {@link Subscriber}. Will retain onNext signal for up to the given * {@link Duration} with a per-item ttl. *

* Completion and Error will also be replayed until {@code ttl} triggers in which case * the next {@link Subscriber} will start over a new subscription *

* * * @param ttl Per-item and post termination timeout duration * @param timer a time-capable {@link Scheduler} instance to read current time from * * @return a replaying {@link ConnectableFlux} */ public final ConnectableFlux replay(Duration ttl, Scheduler timer) { return replay(Integer.MAX_VALUE, ttl, timer); } /** * Turn this {@link Flux} into a connectable hot source and cache last emitted signals * for further {@link Subscriber}. Will retain up to the given history size onNext * signals with a per-item ttl. *

* Completion and Error will also be replayed until {@code ttl} triggers in which case * the next {@link Subscriber} will start over a new subscription *

* * * @param history number of events retained in history excluding complete and error * @param ttl Per-item and post termination timeout duration * @param timer a {@link Scheduler} instance to read current time from * * @return a replaying {@link ConnectableFlux} */ public final ConnectableFlux replay(int history, Duration ttl, Scheduler timer) { Objects.requireNonNull(timer, "timer"); return onAssembly(new FluxReplay<>(this, history, ttl.toMillis(), timer)); } /** * Re-subscribes to this {@link Flux} sequence if it signals any error, indefinitely. *

* * * @return a {@link Flux} that retries on onError */ public final Flux retry() { return retry(Long.MAX_VALUE); } /** * Re-subscribes to this {@link Flux} sequence if it signals any error, for a fixed * number of times. *

* Note that passing {@literal Long.MAX_VALUE} is treated as infinite retry. *

* * * @param numRetries the number of times to tolerate an error * * @return a {@link Flux} that retries on onError up to the specified number of retry attempts. * */ public final Flux retry(long numRetries) { return onAssembly(new FluxRetry<>(this, numRetries)); } /** * Re-subscribes to this {@link Flux} sequence if it signals any error * that matches the given {@link Predicate}, otherwise push the error downstream. * *

* * * @param retryMatcher the predicate to evaluate if retry should occur based on a given error signal * * @return a {@link Flux} that retries on onError if the predicates matches. */ public final Flux retry(Predicate retryMatcher) { return onAssembly(new FluxRetryPredicate<>(this, retryMatcher)); } /** * Re-subscribes to this {@link Flux} sequence up to the specified number of retries if it signals any * error that match the given {@link Predicate}, otherwise push the error downstream. * *

* * * @param numRetries the number of times to tolerate an error * @param retryMatcher the predicate to evaluate if retry should occur based on a given error signal * * @return a {@link Flux} that retries on onError up to the specified number of retry * attempts, only if the predicate matches. */ public final Flux retry(long numRetries, Predicate retryMatcher) { return defer(() -> retry(countingPredicate(retryMatcher, numRetries))); } /** * Retries this {@link Flux} when a companion sequence signals * an item in response to this {@link Flux} error signal *

If the companion sequence signals when the {@link Flux} is active, the retry * attempt is suppressed and any terminal signal will terminate the {@link Flux} source with the same signal * immediately. * *

* * * @param whenFactory the {@link Function} that returns the associated {@link Publisher} * companion, given a {@link Flux} that signals each onError as a {@link Throwable}. * * @return a {@link Flux} that retries on onError when the companion {@link Publisher} produces an * onNext signal */ public final Flux retryWhen(Function, ? extends Publisher> whenFactory) { return onAssembly(new FluxRetryWhen<>(this, whenFactory)); } /** * Sample this {@link Flux} by periodically emitting an item corresponding to that * {@link Flux} latest emitted value within the periodical time window. * Note that if some elements are emitted quicker than the timespan just before source * completion, the last of these elements will be emitted along with the onComplete * signal. * *

* * * @param timespan the duration of the window after which to emit the latest observed item * * @return a {@link Flux} sampled to the last item seen over each periodic window */ public final Flux sample(Duration timespan) { return sample(interval(timespan)); } /** * Sample this {@link Flux} by emitting an item corresponding to that {@link Flux} * latest emitted value whenever a companion sampler {@link Publisher} signals a value. *

* Termination of either {@link Publisher} will result in termination for the {@link Subscriber} * as well. * Note that if some elements are emitted just before source completion and before a * last sampler can trigger, the last of these elements will be emitted along with the * onComplete signal. *

* Both {@link Publisher} will run in unbounded mode because the backpressure * would interfere with the sampling precision. * *

* * * @param sampler the sampler companion {@link Publisher} * * @param the type of the sampler sequence * * @return a {@link Flux} sampled to the last item observed each time the sampler {@link Publisher} signals */ public final Flux sample(Publisher sampler) { return onAssembly(new FluxSample<>(this, sampler)); } /** * Repeatedly take a value from this {@link Flux} then skip the values that follow * within a given duration. * *

* * * @param timespan the duration during which to skip values after each sample * * @return a {@link Flux} sampled to the first item of each duration-based window */ public final Flux sampleFirst(Duration timespan) { return sampleFirst(t -> Mono.delay(timespan)); } /** * Repeatedly take a value from this {@link Flux} then skip the values that follow * before the next signal from a companion sampler {@link Publisher}. * *

* * * @param samplerFactory supply a companion sampler {@link Publisher} which signals the end of the skip window * @param the companion reified type * * @return a {@link Flux} sampled to the first item observed in each window closed by the sampler signals */ public final Flux sampleFirst(Function> samplerFactory) { return onAssembly(new FluxSampleFirst<>(this, samplerFactory)); } /** * Emit the latest value from this {@link Flux} only if there were no new values emitted * during the window defined by a companion {@link Publisher} derived from that particular * value. *

* Note that this means that the last value in the sequence is always emitted. * *

* * * @param throttlerFactory supply a companion sampler {@link Publisher} which signals * the end of the window during which no new emission should occur. If it is the case, * the original value triggering the window is emitted. * @param the companion reified type * * @return a {@link Flux} sampled to items not followed by any other item within a window * defined by a companion {@link Publisher} */ public final Flux sampleTimeout(Function> throttlerFactory) { return sampleTimeout(throttlerFactory, Queues.XS_BUFFER_SIZE); } /** * Emit the latest value from this {@link Flux} only if there were no new values emitted * during the window defined by a companion {@link Publisher} derived from that particular * value. *

The provided {@literal maxConcurrency} will keep a bounded maximum of concurrent timeouts and drop any new * items until at least one timeout terminates. *

* Note that this means that the last value in the sequence is always emitted. * *

* * * @param throttlerFactory supply a companion sampler {@link Publisher} which signals * the end of the window during which no new emission should occur. If it is the case, * the original value triggering the window is emitted. * @param maxConcurrency the maximum number of concurrent timeouts * @param the throttling type * * @return a {@link Flux} sampled to items not followed by any other item within a window * defined by a companion {@link Publisher} */ public final Flux sampleTimeout(Function> throttlerFactory, int maxConcurrency) { return onAssembly(new FluxSampleTimeout<>(this, throttlerFactory, Queues.get(maxConcurrency))); } /** * Reduce this {@link Flux} values with an accumulator {@link BiFunction} and * also emit the intermediate results of this function. *

* Unlike {@link #scan(Object, BiFunction)}, this operator doesn't take an initial value * but treats the first {@link Flux} value as initial value. *
* The accumulation works as follows: *


	 * result[0] = source[0]
	 * result[1] = accumulator(result[0], source[1])
	 * result[2] = accumulator(result[1], source[2])
	 * result[3] = accumulator(result[2], source[3])
	 * ...
	 * 
* *

* * * @param accumulator the accumulating {@link BiFunction} * * @return an accumulating {@link Flux} */ public final Flux scan(BiFunction accumulator) { return onAssembly(new FluxScan<>(this, accumulator)); } /** * Reduce this {@link Flux} values with an accumulator {@link BiFunction} and * also emit the intermediate results of this function. *

* The accumulation works as follows: *


	 * result[0] = initialValue;
	 * result[1] = accumulator(result[0], source[0])
	 * result[2] = accumulator(result[1], source[1])
	 * result[3] = accumulator(result[2], source[2])
	 * ...
	 * 
* *

* * * @param initial the initial leftmost argument to pass to the reduce function * @param accumulator the accumulating {@link BiFunction} * @param the accumulated type * * @return an accumulating {@link Flux} starting with initial state * */ public final Flux scan(A initial, BiFunction accumulator) { Objects.requireNonNull(initial, "seed"); return scanWith(() -> initial, accumulator); } /** * Reduce this {@link Flux} values with the help of an accumulator {@link BiFunction} * and also emits the intermediate results. A seed value is lazily provided by a * {@link Supplier} invoked for each {@link Subscriber}. *

* The accumulation works as follows: *


	 * result[0] = initialValue;
	 * result[1] = accumulator(result[0], source[0])
	 * result[2] = accumulator(result[1], source[1])
	 * result[3] = accumulator(result[2], source[2])
	 * ...
	 * 
* *

* * * @param initial the supplier providing the seed, the leftmost parameter initially * passed to the reduce function * @param accumulator the accumulating {@link BiFunction} * @param the accumulated type * * @return an accumulating {@link Flux} starting with initial state * */ public final Flux scanWith(Supplier initial, BiFunction accumulator) { return onAssembly(new FluxScanSeed<>(this, initial, accumulator)); } /** * Returns a new {@link Flux} that multicasts (shares) the original {@link Flux}. * As long as there is at least one {@link Subscriber} this {@link Flux} will be subscribed and * emitting data. * When all subscribers have cancelled it will cancel the source * {@link Flux}. *

This is an alias for {@link #publish()}.{@link ConnectableFlux#refCount()}. * * @return a {@link Flux} that upon first subscribe causes the source {@link Flux} * to subscribe once, late subscribers might therefore miss items. */ public final Flux share() { return onAssembly(new FluxRefCount<>( new FluxPublish<>(this, Queues.SMALL_BUFFER_SIZE, Queues.small()), 1) ); } /** * Expect and emit a single item from this {@link Flux} source or signal * {@link java.util.NoSuchElementException} for an empty source, or * {@link IndexOutOfBoundsException} for a source with more than one element. * *

* * * @return a {@link Mono} with the single item or an error signal */ public final Mono single() { if (this instanceof Callable) { if (this instanceof Fuseable.ScalarCallable) { @SuppressWarnings("unchecked") Fuseable.ScalarCallable scalarCallable = (Fuseable.ScalarCallable) this; T v; try { v = scalarCallable.call(); } catch (Exception e) { return Mono.error(e); } if (v == null) { return Mono.error(new NoSuchElementException("Source was a (constant) empty")); } return Mono.just(v); } @SuppressWarnings("unchecked") Callable thiz = (Callable)this; return Mono.onAssembly(new MonoCallable<>(thiz)); } return Mono.onAssembly(new MonoSingle<>(this)); } /** * Expect and emit a single item from this {@link Flux} source and emit a default * value for an empty source, but signal an {@link IndexOutOfBoundsException} for a * source with more than one element. * *

* * @param defaultValue a single fallback item if this {@link Flux} is empty * * @return a {@link Mono} with the expected single item, the supplied default value or * and error signal */ public final Mono single(T defaultValue) { if (this instanceof Callable) { if (this instanceof Fuseable.ScalarCallable) { @SuppressWarnings("unchecked") Fuseable.ScalarCallable scalarCallable = (Fuseable.ScalarCallable) this; T v; try { v = scalarCallable.call(); } catch (Exception e) { return Mono.error(e); } if (v == null) { return Mono.just(defaultValue); } return Mono.just(v); } @SuppressWarnings("unchecked") Callable thiz = (Callable)this; return Mono.onAssembly(new MonoCallable<>(thiz)); } return Mono.onAssembly(new MonoSingle<>(this, defaultValue, false)); } /** * Expect and emit a single item from this {@link Flux} source, and accept an empty * source but signal an {@link IndexOutOfBoundsException} for a source with more than * one element. *

* * * @return a {@link Mono} with the expected single item, no item or an error */ public final Mono singleOrEmpty() { if (this instanceof Callable) { @SuppressWarnings("unchecked") Callable thiz = (Callable)this; return convertToMono(thiz); } return Mono.onAssembly(new MonoSingle<>(this, null, true)); } /** * Skip the specified number of elements from the beginning of this {@link Flux} then * emit the remaining elements. * *

* * * @param skipped the number of elements to drop * * @return a dropping {@link Flux} with the specified number of elements skipped at * the beginning */ public final Flux skip(long skipped) { if (skipped == 0L) { return this; } else { return onAssembly(new FluxSkip<>(this, skipped)); } } /** * Skip elements from this {@link Flux} emitted within the specified initial duration. * *

* * * @param timespan the initial time window during which to drop elements * * @return a {@link Flux} dropping at the beginning until the end of the given duration */ public final Flux skip(Duration timespan) { return skip(timespan, Schedulers.parallel()); } /** * Skip elements from this {@link Flux} emitted within the specified initial duration, * as measured on the provided {@link Scheduler}. * *

* * * @param timespan the initial time window during which to drop elements * @param timer a time-capable {@link Scheduler} instance to measure the time window on * * @return a {@link Flux} dropping at the beginning for the given duration */ public final Flux skip(Duration timespan, Scheduler timer) { if(!timespan.isZero()) { return skipUntilOther(Mono.delay(timespan, timer)); } else{ return this; } } /** * Skip a specified number of elements at the end of this {@link Flux} sequence. * *

* * * @param n the number of elements to drop before completion * * @return a {@link Flux} dropping the specified number of elements at the end of the * sequence * */ public final Flux skipLast(int n) { if (n == 0) { return this; } return onAssembly(new FluxSkipLast<>(this, n)); } /** * Skips values from this {@link Flux} until a {@link Predicate} returns true for the * value. The resulting {@link Flux} will include and emit the matching value. * *

* * * @param untilPredicate the {@link Predicate} evaluated to stop skipping. * * @return a {@link Flux} dropping until the {@link Predicate} matches */ public final Flux skipUntil(Predicate untilPredicate) { return onAssembly(new FluxSkipUntil<>(this, untilPredicate)); } /** * Skip values from this {@link Flux} until a specified {@link Publisher} signals * an onNext or onComplete. * *

* * * @param other the companion {@link Publisher} to coordinate with to stop skipping * * @return a {@link Flux} dropping until the other {@link Publisher} emits * */ public final Flux skipUntilOther(Publisher other) { return onAssembly(new FluxSkipUntilOther<>(this, other)); } /** * Skips values from this {@link Flux} while a {@link Predicate} returns true for the value. * *

* * * @param skipPredicate the {@link Predicate} that causes skipping while evaluating to true. * * @return a {@link Flux} dropping while the {@link Predicate} matches */ public final Flux skipWhile(Predicate skipPredicate) { return onAssembly(new FluxSkipWhile<>(this, skipPredicate)); } /** * Sort elements from this {@link Flux} by collecting and sorting them in the background * then emitting the sorted sequence once this sequence completes. * Each item emitted by the {@link Flux} must implement {@link Comparable} with * respect to all other items in the sequence. * *

Note that calling {@code sort} with long, non-terminating or infinite sources * might cause {@link OutOfMemoryError}. Use sequence splitting like {@link #window} to sort batches in that case. * * @throws ClassCastException if any item emitted by the {@link Flux} does not implement * {@link Comparable} with respect to all other items emitted by the {@link Flux} * @return a sorted {@link Flux} */ public final Flux sort(){ return collectSortedList().flatMapIterable(identityFunction()); } /** * Sort elements from this {@link Flux} using a {@link Comparator} function, by * collecting and sorting elements in the background then emitting the sorted sequence * once this sequence completes. * *

Note that calling {@code sort} with long, non-terminating or infinite sources * might cause {@link OutOfMemoryError} * * @param sortFunction a function that compares two items emitted by this {@link Flux} * to indicate their sort order * @return a sorted {@link Flux} */ public final Flux sort(Comparator sortFunction) { return collectSortedList(sortFunction).flatMapIterable(identityFunction()); } /** * Prepend the given {@link Iterable} before this {@link Flux} sequence. * *

* * * @param iterable the sequence of values to start the resulting {@link Flux} with * * @return a new {@link Flux} prefixed with elements from an {@link Iterable} */ public final Flux startWith(Iterable iterable) { return startWith(fromIterable(iterable)); } /** * Prepend the given values before this {@link Flux} sequence. * *

* * * @param values the array of values to start the resulting {@link Flux} with * * @return a new {@link Flux} prefixed with the given elements */ @SafeVarargs public final Flux startWith(T... values) { return startWith(just(values)); } /** * Prepend the given {@link Publisher} sequence to this {@link Flux} sequence. * *

* * * @param publisher the Publisher whose values to prepend * * @return a new {@link Flux} prefixed with the given {@link Publisher} sequence */ public final Flux startWith(Publisher publisher) { if (this instanceof FluxConcatArray) { FluxConcatArray fluxConcatArray = (FluxConcatArray) this; return fluxConcatArray.concatAdditionalSourceFirst(publisher); } return concat(publisher, this); } /** * Subscribe to this {@link Flux} and request unbounded demand. *

* This version doesn't specify any consumption behavior for the events from the * chain, especially no error handling, so other variants should usually be preferred. * *

* *

* * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} */ public final Disposable subscribe() { return subscribe(null, null, null); } /** * Subscribe a {@link Consumer} to this {@link Flux} that will consume all the * elements in the sequence. It will request an unbounded demand ({@code Long.MAX_VALUE}). *

* For a passive version that observe and forward incoming data see {@link #doOnNext(java.util.function.Consumer)}. *

* For a version that gives you more control over backpressure and the request, see * {@link #subscribe(Subscriber)} with a {@link BaseSubscriber}. *

* Keep in mind that since the sequence can be asynchronous, this will immediately * return control to the calling thread. This can give the impression the consumer is * not invoked when executing in a main thread or a unit test for instance. * *

* * * @param consumer the consumer to invoke on each value (onNext signal) * * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} */ public final Disposable subscribe(Consumer consumer) { Objects.requireNonNull(consumer, "consumer"); return subscribe(consumer, null, null); } /** * Subscribe to this {@link Flux} with a {@link Consumer} that will consume all the * elements in the sequence, as well as a {@link Consumer} that will handle errors. * The subscription will request an unbounded demand ({@code Long.MAX_VALUE}). *

* For a passive version that observe and forward incoming data see * {@link #doOnNext(java.util.function.Consumer)} and {@link #doOnError(java.util.function.Consumer)}. *

For a version that gives you more control over backpressure and the request, see * {@link #subscribe(Subscriber)} with a {@link BaseSubscriber}. *

* Keep in mind that since the sequence can be asynchronous, this will immediately * return control to the calling thread. This can give the impression the consumers are * not invoked when executing in a main thread or a unit test for instance. * *

* * * @param consumer the consumer to invoke on each next signal * @param errorConsumer the consumer to invoke on error signal * * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} */ public final Disposable subscribe(@Nullable Consumer consumer, Consumer errorConsumer) { Objects.requireNonNull(errorConsumer, "errorConsumer"); return subscribe(consumer, errorConsumer, null); } /** * Subscribe {@link Consumer} to this {@link Flux} that will respectively consume all the * elements in the sequence, handle errors and react to completion. The subscription * will request unbounded demand ({@code Long.MAX_VALUE}). *

* For a passive version that observe and forward incoming data see {@link #doOnNext(java.util.function.Consumer)}, * {@link #doOnError(java.util.function.Consumer)} and {@link #doOnComplete(Runnable)}. *

For a version that gives you more control over backpressure and the request, see * {@link #subscribe(Subscriber)} with a {@link BaseSubscriber}. *

* Keep in mind that since the sequence can be asynchronous, this will immediately * return control to the calling thread. This can give the impression the consumer is * not invoked when executing in a main thread or a unit test for instance. * *

* * * @param consumer the consumer to invoke on each value * @param errorConsumer the consumer to invoke on error signal * @param completeConsumer the consumer to invoke on complete signal * * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} */ public final Disposable subscribe( @Nullable Consumer consumer, @Nullable Consumer errorConsumer, @Nullable Runnable completeConsumer) { return subscribe(consumer, errorConsumer, completeConsumer, null); } /** * Subscribe {@link Consumer} to this {@link Flux} that will respectively consume all the * elements in the sequence, handle errors, react to completion, and request upon subscription. * It will let the provided {@link Subscription subscriptionConsumer} * request the adequate amount of data, or request unbounded demand * {@code Long.MAX_VALUE} if no such consumer is provided. *

* For a passive version that observe and forward incoming data see {@link #doOnNext(java.util.function.Consumer)}, * {@link #doOnError(java.util.function.Consumer)}, {@link #doOnComplete(Runnable)} * and {@link #doOnSubscribe(Consumer)}. *

For a version that gives you more control over backpressure and the request, see * {@link #subscribe(Subscriber)} with a {@link BaseSubscriber}. *

* Keep in mind that since the sequence can be asynchronous, this will immediately * return control to the calling thread. This can give the impression the consumer is * not invoked when executing in a main thread or a unit test for instance. * *

* * * @param consumer the consumer to invoke on each value * @param errorConsumer the consumer to invoke on error signal * @param completeConsumer the consumer to invoke on complete signal * @param subscriptionConsumer the consumer to invoke on subscribe signal, to be used * for the initial {@link Subscription#request(long) request}, or null for max request * * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} */ public final Disposable subscribe( @Nullable Consumer consumer, @Nullable Consumer errorConsumer, @Nullable Runnable completeConsumer, @Nullable Consumer subscriptionConsumer) { return subscribeWith(new LambdaSubscriber<>(consumer, errorConsumer, completeConsumer, subscriptionConsumer)); } @Override public final void subscribe(Subscriber actual) { onLastAssembly(this).subscribe(Operators.toCoreSubscriber(actual)); } /** * An internal {@link Publisher#subscribe(Subscriber)} that will bypass * {@link Hooks#onLastOperator(Function)} pointcut. *

* In addition to behave as expected by {@link Publisher#subscribe(Subscriber)} * in a controlled manner, it supports direct subscribe-time {@link Context} passing. * * @param actual the {@link Subscriber} interested into the published sequence * @see Flux#subscribe(Subscriber) */ public abstract void subscribe(CoreSubscriber actual); /** * Enrich a potentially empty downstream {@link Context} by adding all values * from the given {@link Context}, producing a new {@link Context} that is propagated * upstream. *

* The {@link Context} propagation happens once per subscription (not on each onNext): * it is done during the {@code subscribe(Subscriber)} phase, which runs from * the last operator of a chain towards the first. *

* So this operator enriches a {@link Context} coming from under it in the chain * (downstream, by default an empty one) and passes the new enriched {@link Context} * to operators above it in the chain (upstream, by way of them using * {@code Flux#subscribe(Subscriber,Context)}). * * @param mergeContext the {@link Context} to merge with a previous {@link Context} * state, returning a new one. * * @return a contextualized {@link Flux} * @see Context */ public final Flux subscriberContext(Context mergeContext) { return subscriberContext(c -> c.putAll(mergeContext)); } /** * Enrich a potentially empty downstream {@link Context} by applying a {@link Function} * to it, producing a new {@link Context} that is propagated upstream. *

* The {@link Context} propagation happens once per subscription (not on each onNext): * it is done during the {@code subscribe(Subscriber)} phase, which runs from * the last operator of a chain towards the first. *

* So this operator enriches a {@link Context} coming from under it in the chain * (downstream, by default an empty one) and passes the new enriched {@link Context} * to operators above it in the chain (upstream, by way of them using * {@code Flux#subscribe(Subscriber,Context)}). * * * @param doOnContext the function taking a previous {@link Context} state * and returning a new one. * * @return a contextualized {@link Flux} * @see Context */ public final Flux subscriberContext(Function doOnContext) { return new FluxContextStart<>(this, doOnContext); } /** * Run subscribe, onSubscribe and request on a specified {@link Scheduler}'s {@link Worker}. * As such, placing this operator anywhere in the chain will also impact the execution * context of onNext/onError/onComplete signals from the beginning of the chain up to * the next occurrence of a {@link #publishOn(Scheduler) publishOn}. *

* Note that if you are using an eager or blocking * {@link #create(Consumer, FluxSink.OverflowStrategy)} * as the source, it can lead to deadlocks due to requests piling up behind the emitter. * In such case, you should call {@link #subscribeOn(Scheduler, boolean) subscribeOn(scheduler, false)} * instead. *

* *

* Typically used for slow publisher e.g., blocking IO, fast consumer(s) scenarios. * *

	 * {@code flux.subscribeOn(Schedulers.single()).subscribe() }
	 * 
* *

* Note that {@link Worker#schedule(Runnable)} raising * {@link java.util.concurrent.RejectedExecutionException} on late * {@link Subscription#request(long)} will be propagated to the request caller. * * @param scheduler a {@link Scheduler} providing the {@link Worker} where to subscribe * * @return a {@link Flux} requesting asynchronously * @see #publishOn(Scheduler) * @see #subscribeOn(Scheduler, boolean) */ public final Flux subscribeOn(Scheduler scheduler) { return subscribeOn(scheduler, true); } /** * Run subscribe and onSubscribe on a specified {@link Scheduler}'s {@link Worker}. * Request will be run on that worker too depending on the {@code requestOnSeparateThread} * parameter (which defaults to true in the {@link #subscribeOn(Scheduler)} version). * As such, placing this operator anywhere in the chain will also impact the execution * context of onNext/onError/onComplete signals from the beginning of the chain up to * the next occurrence of a {@link #publishOn(Scheduler) publishOn}. *

* Note that if you are using an eager or blocking * {@link Flux#create(Consumer, FluxSink.OverflowStrategy)} * as the source, it can lead to deadlocks due to requests piling up behind the emitter. * Thus this operator has a {@code requestOnSeparateThread} parameter, which should be * set to {@code false} in this case. *

* *

* Typically used for slow publisher e.g., blocking IO, fast consumer(s) scenarios. * *

	 * {@code flux.subscribeOn(Schedulers.single()).subscribe() }
	 * 
* *

* Note that {@link Worker#schedule(Runnable)} raising * {@link java.util.concurrent.RejectedExecutionException} on late * {@link Subscription#request(long)} will be propagated to the request caller. * * @param scheduler a {@link Scheduler} providing the {@link Worker} where to subscribe * @param requestOnSeparateThread whether or not to also perform requests on the worker. * {@code true} to behave like {@link #subscribeOn(Scheduler)} * * @return a {@link Flux} requesting asynchronously * @see #publishOn(Scheduler) * @see #subscribeOn(Scheduler) */ public final Flux subscribeOn(Scheduler scheduler, boolean requestOnSeparateThread) { if (this instanceof Callable) { if (this instanceof Fuseable.ScalarCallable) { try { @SuppressWarnings("unchecked") T value = ((Fuseable.ScalarCallable) this).call(); return onAssembly(new FluxSubscribeOnValue<>(value, scheduler)); } catch (Exception e) { //leave FluxSubscribeOnCallable defer error } } @SuppressWarnings("unchecked") Callable c = (Callable)this; return onAssembly(new FluxSubscribeOnCallable<>(c, scheduler)); } return onAssembly(new FluxSubscribeOn<>(this, scheduler, requestOnSeparateThread)); } /** * Subscribe the given {@link Subscriber} to this {@link Flux} and return said * {@link Subscriber} (eg. a {@link FluxProcessor}). * *

	 * {@code flux.subscribeWith(WorkQueueProcessor.create()).subscribe() }
	 * 
* * If you need more control over backpressure and the request, use a {@link BaseSubscriber}. * * @param subscriber the {@link Subscriber} to subscribe with and return * @param the reified type from the input/output subscriber * * @return the passed {@link Subscriber} */ public final > E subscribeWith(E subscriber) { subscribe(subscriber); return subscriber; } /** * Switch to an alternative {@link Publisher} if this sequence is completed without any data. *

* *

* @param alternate the alternative {@link Publisher} if this sequence is empty * * @return a new {@link Flux} that falls back on a {@link Publisher} if source is empty */ public final Flux switchIfEmpty(Publisher alternate) { return onAssembly(new FluxSwitchIfEmpty<>(this, alternate)); } /** * Switch to a new {@link Publisher} generated via a {@link Function} whenever * this {@link Flux} produces an item. As such, the elements from each generated * Publisher are emitted in the resulting {@link Flux}. * *

* * * @param fn the {@link Function} to generate a {@link Publisher} for each source value * @param the type of the return value of the transformation function * * @return a new {@link Flux} that emits values from an alternative {@link Publisher} * for each source onNext * */ public final Flux switchMap(Function> fn) { return switchMap(fn, Queues.XS_BUFFER_SIZE); } /** * Switch to a new {@link Publisher} generated via a {@link Function} whenever * this {@link Flux} produces an item. As such, the elements from each generated * Publisher are emitted in the resulting {@link Flux}. * *

* * * @param fn the {@link Function} to generate a {@link Publisher} for each source value * @param prefetch the produced demand for inner sources * * @param the type of the return value of the transformation function * * @return a new {@link Flux} that emits values from an alternative {@link Publisher} * for each source onNext */ public final Flux switchMap(Function> fn, int prefetch) { return onAssembly(new FluxSwitchMap<>(this, fn, Queues.unbounded(prefetch), prefetch)); } /** * Tag this flux with a key/value pair. These can be retrieved as a {@link Set} of * all tags throughout the publisher chain by using {@link Scannable#tags()} (as * traversed * by {@link Scannable#parents()}). * * @param key a tag key * @param value a tag value * @return the same sequence, but bearing tags */ public final Flux tag(String key, String value) { return FluxName.createOrAppend(this, key, value); } /** * Take only the first N values from this {@link Flux}, if available. *

* *

* If N is zero, the resulting {@link Flux} completes as soon as this {@link Flux} * signals its first value (which is not not relayed, though). *

* Note that this operator doesn't manipulate the backpressure requested amount. * Rather, it merely lets requests from downstream propagate as is and cancels once * N elements have been emitted. As a result, the source could produce a lot of * extraneous elements in the meantime. If that behavior is undesirable and you do * not own the request from downstream (e.g. prefetching operators), consider * using {@link #limitRequest(long)} instead. * *

* * @param n the number of items to emit from this {@link Flux} * * @return a {@link Flux} limited to size N * @see #limitRequest(long) */ public final Flux take(long n) { if (this instanceof Fuseable) { return onAssembly(new FluxTakeFuseable<>(this, n)); } return onAssembly(new FluxTake<>(this, n)); } /** * Relay values from this {@link Flux} until the specified {@link Duration} elapses. *

* If the duration is zero, the resulting {@link Flux} completes as soon as this {@link Flux} * signals its first value (which is not not relayed, though). * *

* * * @param timespan the {@link Duration} of the time window during which to emit elements * from this {@link Flux} * * @return a {@link Flux} limited to elements emitted within a specific duration */ public final Flux take(Duration timespan) { return take(timespan, Schedulers.parallel()); } /** * Relay values from this {@link Flux} until the specified {@link Duration} elapses, * as measured on the specified {@link Scheduler}. *

* If the duration is zero, the resulting {@link Flux} completes as soon as this {@link Flux} * signals its first value (which is not not relayed, though). * *

* * * @param timespan the {@link Duration} of the time window during which to emit elements * from this {@link Flux} * @param timer a time-capable {@link Scheduler} instance to run on * * @return a {@link Flux} limited to elements emitted within a specific duration */ public final Flux take(Duration timespan, Scheduler timer) { if (!timespan.isZero()) { return takeUntilOther(Mono.delay(timespan, timer)); } else { return take(0); } } /** * Emit the last N values this {@link Flux} emitted before its completion. * *

* * * @param n the number of items from this {@link Flux} to retain and emit on onComplete * * @return a terminating {@link Flux} sub-sequence * */ public final Flux takeLast(int n) { if(n == 1){ return onAssembly(new FluxTakeLastOne<>(this)); } return onAssembly(new FluxTakeLast<>(this, n)); } /** * Relay values from this {@link Flux} until the given {@link Predicate} matches. * This includes the matching data (unlike {@link #takeWhile}). * *

* * * @param predicate the {@link Predicate} that stops the taking of values from this {@link Flux} * when returning {@literal true}. * * @return a new {@link Flux} limited by the predicate * */ public final Flux takeUntil(Predicate predicate) { return onAssembly(new FluxTakeUntil<>(this, predicate)); } /** * Relay values from this {@link Flux} until the given {@link Publisher} emits. * *

* * * @param other the companion {@link Publisher} that signals when to stop taking values from this {@link Flux} * * @return a new {@link Flux} limited by a companion {@link Publisher} * */ public final Flux takeUntilOther(Publisher other) { return onAssembly(new FluxTakeUntilOther<>(this, other)); } /** * Relay values from this {@link Flux} while a predicate returns {@literal TRUE} * for the values (checked before each value is delivered). * This only includes the matching data (unlike {@link #takeUntil}). * *

* * * @param continuePredicate the {@link Predicate} invoked each onNext returning {@literal TRUE} * to relay a value or {@literal FALSE} to terminate * * @return a new {@link Flux} taking values from the source while the predicate matches */ public final Flux takeWhile(Predicate continuePredicate) { return onAssembly(new FluxTakeWhile<>(this, continuePredicate)); } /** * Return a {@code Mono} that completes when this {@link Flux} completes. * This will actively ignore the sequence and only replay completion or error signals. *

* *

* @return a new {@link Mono} representing the termination of this {@link Flux} */ public final Mono then() { @SuppressWarnings("unchecked") Mono then = (Mono) new MonoIgnoreElements<>(this); return Mono.onAssembly(then); } /** * Let this {@link Flux} complete then play signals from a provided {@link Mono}. *

* In other words ignore element from this {@link Flux} and transform its completion signal into the * emission and completion signal of a provided {@code Mono}. Error signal is * replayed in the resulting {@code Mono}. * *

* * * @param other a {@link Mono} to emit from after termination * @param the element type of the supplied Mono * * @return a new {@link Flux} that wait for source completion then emits from the supplied {@link Mono} */ public final Mono then(Mono other) { return Mono.onAssembly(new MonoIgnoreThen<>(new Publisher[] { this }, other)); } /** * Return a {@code Mono} that waits for this {@link Flux} to complete then * for a supplied {@link Publisher Publisher<Void>} to also complete. The * second completion signal is replayed, or any error signal that occurs instead. *

* * * @param other a {@link Publisher} to wait for after this Flux's termination * @return a new {@link Mono} completing when both publishers have completed in * sequence */ public final Mono thenEmpty(Publisher other) { return then(Mono.fromDirect(other)); } /** * Let this {@link Flux} complete then play another {@link Publisher}. *

* In other words ignore element from this flux and transform the completion signal into a * {@code Publisher} that will emit elements from the provided {@link Publisher}. *

* * * @param other a {@link Publisher} to emit from after termination * @param the element type of the supplied Publisher * * @return a new {@link Flux} that emits from the supplied {@link Publisher} after * this Flux completes. */ public final Flux thenMany(Publisher other) { if (this instanceof FluxConcatArray) { @SuppressWarnings({ "unchecked" }) FluxConcatArray fluxConcatArray = (FluxConcatArray) this; return fluxConcatArray.concatAdditionalIgnoredLast(other); } @SuppressWarnings("unchecked") Flux concat = (Flux)concat(ignoreElements(), other); return concat; } /** * Propagate a {@link TimeoutException} as soon as no item is emitted within the * given {@link Duration} from the previous emission (or the subscription for the first item). * *

* * * @param timeout the timeout between two signals from this {@link Flux} * * @return a {@link Flux} that can time out on a per-item basis */ public final Flux timeout(Duration timeout) { return timeout(timeout, null, Schedulers.parallel()); } /** * Switch to a fallback {@link Flux} as soon as no item is emitted within the * given {@link Duration} from the previous emission (or the subscription for the first item). *

* If the given {@link Publisher} is null, signal a {@link TimeoutException} instead. * *

* * * @param timeout the timeout between two signals from this {@link Flux} * @param fallback the fallback {@link Publisher} to subscribe when a timeout occurs * * @return a {@link Flux} that will fallback to a different {@link Publisher} in case of a per-item timeout */ public final Flux timeout(Duration timeout, @Nullable Publisher fallback) { return timeout(timeout, fallback, Schedulers.parallel()); } /** * Propagate a {@link TimeoutException} as soon as no item is emitted within the * given {@link Duration} from the previous emission (or the subscription for the first * item), as measured by the specified {@link Scheduler}. * *

* * * @param timeout the timeout {@link Duration} between two signals from this {@link Flux} * @param timer a time-capable {@link Scheduler} instance to run on * * @return a {@link Flux} that can time out on a per-item basis */ public final Flux timeout(Duration timeout, Scheduler timer) { return timeout(timeout, null, timer); } /** * Switch to a fallback {@link Flux} as soon as no item is emitted within the * given {@link Duration} from the previous emission (or the subscription for the * first item), as measured on the specified {@link Scheduler}. *

* If the given {@link Publisher} is null, signal a {@link TimeoutException} instead. * *

* * * @param timeout the timeout {@link Duration} between two signals from this {@link Flux} * @param fallback the fallback {@link Publisher} to subscribe when a timeout occurs * @param timer a time-capable {@link Scheduler} instance to run on * * @return a {@link Flux} that will fallback to a different {@link Publisher} in case of a per-item timeout */ public final Flux timeout(Duration timeout, @Nullable Publisher fallback, Scheduler timer) { final Mono _timer = Mono.delay(timeout, timer).onErrorReturn(0L); final Function> rest = o -> _timer; if(fallback == null) { return timeout(_timer, rest); } return timeout(_timer, rest, fallback); } /** * Signal a {@link TimeoutException} in case the first item from this {@link Flux} has * not been emitted before the given {@link Publisher} emits. * *

* * * @param firstTimeout the companion {@link Publisher} that will trigger a timeout if * emitting before the first signal from this {@link Flux} * * @param the type of the timeout Publisher * * @return a {@link Flux} that can time out if the first item does not come before * a signal from a companion {@link Publisher} * */ public final Flux timeout(Publisher firstTimeout) { return timeout(firstTimeout, t -> never()); } /** * Signal a {@link TimeoutException} in case the first item from this {@link Flux} has * not been emitted before the {@code firstTimeout} {@link Publisher} emits, and whenever * each subsequent elements is not emitted before a {@link Publisher} generated from * the latest element signals. * *

* * * @param firstTimeout the timeout {@link Publisher} that must not emit before the first signal from this {@link Flux} * @param nextTimeoutFactory the timeout {@link Publisher} factory for each next item * * @param the type of the elements of the first timeout Publisher * @param the type of the elements of the subsequent timeout Publishers * * @return a {@link Flux} that can time out if each element does not come before * a signal from a per-item companion {@link Publisher} */ public final Flux timeout(Publisher firstTimeout, Function> nextTimeoutFactory) { return onAssembly(new FluxTimeout<>(this, firstTimeout, nextTimeoutFactory)); } /** * Switch to a fallback {@link Publisher} in case the first item from this {@link Flux} has * not been emitted before the {@code firstTimeout} {@link Publisher} emits, and whenever * each subsequent elements is not emitted before a {@link Publisher} generated from * the latest element signals. * *

* * * @param firstTimeout the timeout {@link Publisher} that must not emit before the first signal from this {@link Flux} * @param nextTimeoutFactory the timeout {@link Publisher} factory for each next item * @param fallback the fallback {@link Publisher} to subscribe when a timeout occurs * * @param the type of the elements of the first timeout Publisher * @param the type of the elements of the subsequent timeout Publishers * * @return a {@link Flux} that can time out if each element does not come before * a signal from a per-item companion {@link Publisher} */ public final Flux timeout(Publisher firstTimeout, Function> nextTimeoutFactory, Publisher fallback) { return onAssembly(new FluxTimeout<>(this, firstTimeout, nextTimeoutFactory, fallback)); } /** * Emit a {@link reactor.util.function.Tuple2} pair of T1 the current clock time in * millis (as a {@link Long} measured by the {@link Schedulers#parallel() parallel} * Scheduler) and T2 the emitted data (as a {@code T}), for each item from this {@link Flux}. * *

* * * @return a timestamped {@link Flux} */ public final Flux> timestamp() { return timestamp(Schedulers.parallel()); } /** * Emit a {@link reactor.util.function.Tuple2} pair of T1 the current clock time in * millis (as a {@link Long} measured by the provided {@link Scheduler}) and T2 * the emitted data (as a {@code T}), for each item from this {@link Flux}. * *

* * * @param scheduler the {@link Scheduler} to read time from * @return a timestamped {@link Flux} */ public final Flux> timestamp(Scheduler scheduler) { Objects.requireNonNull(scheduler, "scheduler"); return map(d -> Tuples.of(scheduler.now(TimeUnit.MILLISECONDS), d)); } /** * Transform this {@link Flux} into a lazy {@link Iterable} blocking on * {@link Iterator#next()} calls. * *

* *

* * @return a blocking {@link Iterable} */ public final Iterable toIterable() { return toIterable(Queues.SMALL_BUFFER_SIZE); } /** * Transform this {@link Flux} into a lazy {@link Iterable} blocking on * {@link Iterator#next()} calls. * * @param batchSize the bounded capacity to prefetch from this {@link Flux} or * {@code Integer.MAX_VALUE} for unbounded demand * *

* *

* * @return a blocking {@link Iterable} */ public final Iterable toIterable(int batchSize) { return toIterable(batchSize, null); } /** * Transform this {@link Flux} into a lazy {@link Iterable} blocking on * {@link Iterator#next()} calls. * *

* * * @param batchSize the bounded capacity to prefetch from this {@link Flux} or * {@code Integer.MAX_VALUE} for unbounded demand * @param queueProvider the supplier of the queue implementation to be used for storing * elements emitted faster than the iteration * * @return a blocking {@link Iterable} */ public final Iterable toIterable(int batchSize, @Nullable Supplier> queueProvider) { final Supplier> provider; if(queueProvider == null){ provider = Queues.get(batchSize); } else{ provider = queueProvider; } return new BlockingIterable<>(this, batchSize, provider); } /** * Transform this {@link Flux} into a lazy {@link Stream} blocking for each source * {@link Subscriber#onNext(Object) onNext} call. * *

* * * @return a {@link Stream} of unknown size with onClose attached to {@link Subscription#cancel()} */ public final Stream toStream() { return toStream(Queues.SMALL_BUFFER_SIZE); } /** * Transform this {@link Flux} into a lazy {@link Stream} blocking for each source * {@link Subscriber#onNext(Object) onNext} call. * * @param batchSize the bounded capacity to prefetch from this {@link Flux} or * {@code Integer.MAX_VALUE} for unbounded demand *

* * * @return a {@link Stream} of unknown size with onClose attached to {@link Subscription#cancel()} */ public final Stream toStream(int batchSize) { final Supplier> provider; provider = Queues.get(batchSize); return new BlockingIterable<>(this, batchSize, provider).stream(); } /** * Transform this {@link Flux} in order to generate a target {@link Flux}. Unlike {@link #compose(Function)}, the * provided function is executed as part of assembly. * *

	 * {@code
	 * Function applySchedulers = flux -> flux.subscribeOn(Schedulers.elastic())
	 *                                                    .publishOn(Schedulers.parallel());
	 * flux.transform(applySchedulers).map(v -> v * v).subscribe();}
	 * 
* * @param transformer the {@link Function} to immediately map this {@link Flux} into a target {@link Flux} * instance. * @param the item type in the returned {@link Flux} * * @return a new {@link Flux} * @see #compose(Function) for deferred composition of {@link Flux} for each {@link Subscriber} * @see #as for a loose conversion to an arbitrary type */ public final Flux transform(Function, ? extends Publisher> transformer) { return onAssembly(from(transformer.apply(this))); } /** * Split this {@link Flux} sequence into multiple {@link Flux} windows containing * {@code maxSize} elements (or less for the final window) and starting from the first item. * Each {@link Flux} window will onComplete after {@code maxSize} items have been routed. * *

* * * @param maxSize the maximum number of items to emit in the window before closing it * * @return a {@link Flux} of {@link Flux} windows based on element count */ public final Flux> window(int maxSize) { return onAssembly(new FluxWindow<>(this, maxSize, Queues.get(maxSize))); } /** * Split this {@link Flux} sequence into multiple {@link Flux} windows of size * {@code maxSize}, that each open every {@code skip} elements in the source. * *

* When maxSize < skip : dropping windows *

* *

* When maxSize > skip : overlapping windows *

* *

* When maxSize == skip : exact windows *

* * * @param maxSize the maximum number of items to emit in the window before closing it * @param skip the number of items to count before opening and emitting a new window * * @return a {@link Flux} of {@link Flux} windows based on element count and opened every skipCount */ public final Flux> window(int maxSize, int skip) { return onAssembly(new FluxWindow<>(this, maxSize, skip, Queues.unbounded(Queues.XS_BUFFER_SIZE), Queues.unbounded(Queues.XS_BUFFER_SIZE))); } /** * Split this {@link Flux} sequence into continuous, non-overlapping windows * where the window boundary is signalled by another {@link Publisher} * *

* * * @param boundary a {@link Publisher} to emit any item for a split signal and complete to terminate * * @return a {@link Flux} of {@link Flux} windows delimited by a given {@link Publisher} */ public final Flux> window(Publisher boundary) { return onAssembly(new FluxWindowBoundary<>(this, boundary, Queues.unbounded(Queues.XS_BUFFER_SIZE), Queues.unbounded(Queues.XS_BUFFER_SIZE))); } /** * Split this {@link Flux} sequence into continuous, non-overlapping windows that open * for a {@code timespan} {@link Duration} (as measured on the {@link Schedulers#parallel() parallel} * Scheduler). * *

* * * @param timespan the {@link Duration} to delimit {@link Flux} windows * * @return a {@link Flux} of {@link Flux} windows continuously opened for a given {@link Duration} */ public final Flux> window(Duration timespan) { return window(timespan, Schedulers.parallel()); } /** * Split this {@link Flux} sequence into multiple {@link Flux} windows that open * for a given {@code timespan} {@link Duration}, after which it closes with onComplete. * Each window is opened at a regular {@code timeShift} interval, starting from the * first item. * Both durations are measured on the {@link Schedulers#parallel() parallel} Scheduler. * *

* When timespan < timeshift : dropping windows *

* *

* When timespan > timeshift : overlapping windows *

* *

* When timespan == timeshift : exact windows *

* * * @param timespan the maximum {@link Flux} window {@link Duration} * @param timeshift the period of time at which to create new {@link Flux} windows * * @return a {@link Flux} of {@link Flux} windows opened at regular intervals and * closed after a {@link Duration} * */ public final Flux> window(Duration timespan, Duration timeshift) { return window(timespan, timeshift, Schedulers.parallel()); } /** * Split this {@link Flux} sequence into continuous, non-overlapping windows that open * for a {@code timespan} {@link Duration} (as measured on the provided {@link Scheduler}). * *

* * * @param timespan the {@link Duration} to delimit {@link Flux} windows * @param timer a time-capable {@link Scheduler} instance to run on * * @return a {@link Flux} of {@link Flux} windows continuously opened for a given {@link Duration} */ public final Flux> window(Duration timespan, Scheduler timer) { return window(interval(timespan, timer)); } /** * Split this {@link Flux} sequence into multiple {@link Flux} windows that open * for a given {@code timespan} {@link Duration}, after which it closes with onComplete. * Each window is opened at a regular {@code timeShift} interval, starting from the * first item. * Both durations are measured on the provided {@link Scheduler}. * *

* When timespan < timeshift : dropping windows *

* *

* When timespan > timeshift : overlapping windows *

* *

* When timeshift == timeshift : exact windows *

* * * @param timespan the maximum {@link Flux} window {@link Duration} * @param timeshift the period of time at which to create new {@link Flux} windows * @param timer a time-capable {@link Scheduler} instance to run on * * @return a {@link Flux} of {@link Flux} windows opened at regular intervals and * closed after a {@link Duration} */ public final Flux> window(Duration timespan, Duration timeshift, Scheduler timer) { if (timeshift.equals(timespan)) { return window(timespan); } return windowWhen(interval(Duration.ZERO, timeshift, timer), aLong -> Mono.delay(timespan, timer)); } /** * Split this {@link Flux} sequence into multiple {@link Flux} windows containing * {@code maxSize} elements (or less for the final window) and starting from the first item. * Each {@link Flux} window will onComplete once it contains {@code maxSize} elements * OR it has been open for the given {@link Duration} (as measured on the {@link Schedulers#parallel() parallel} * Scheduler). * *

* * * @param maxSize the maximum number of items to emit in the window before closing it * @param timespan the maximum {@link Duration} since the window was opened before closing it * * @return a {@link Flux} of {@link Flux} windows based on element count and duration */ public final Flux> windowTimeout(int maxSize, Duration timespan) { return windowTimeout(maxSize, timespan , Schedulers.parallel()); } /** * Split this {@link Flux} sequence into multiple {@link Flux} windows containing * {@code maxSize} elements (or less for the final window) and starting from the first item. * Each {@link Flux} window will onComplete once it contains {@code maxSize} elements * OR it has been open for the given {@link Duration} (as measured on the provided * {@link Scheduler}). * *

* * * @param maxSize the maximum number of items to emit in the window before closing it * @param timespan the maximum {@link Duration} since the window was opened before closing it * @param timer a time-capable {@link Scheduler} instance to run on * * @return a {@link Flux} of {@link Flux} windows based on element count and duration */ public final Flux> windowTimeout(int maxSize, Duration timespan, Scheduler timer) { return onAssembly(new FluxWindowTimeout<>(this, maxSize, timespan.toMillis(), timer)); } /** * Split this {@link Flux} sequence into multiple {@link Flux} windows delimited by the * given predicate. A new window is opened each time the predicate returns true, at which * point the previous window will receive the triggering element then onComplete. * *

* * * @param boundaryTrigger a predicate that triggers the next window when it becomes true. * @return a {@link Flux} of {@link Flux} windows, bounded depending * on the predicate. */ public final Flux> windowUntil(Predicate boundaryTrigger) { return windowUntil(boundaryTrigger, false); } /** * Split this {@link Flux} sequence into multiple {@link Flux} windows delimited by the * given predicate. A new window is opened each time the predicate returns true. *

* If {@code cutBefore} is true, the old window will onComplete and the triggering * element will be emitted in the new window. Note it can mean that an empty window is * sometimes emitted, eg. if the first element in the sequence immediately matches the * predicate. *

* *

* Otherwise, the triggering element will be emitted in the old window before it does * onComplete, similar to {@link #windowUntil(Predicate)}. *

* * * @param boundaryTrigger a predicate that triggers the next window when it becomes true. * @param cutBefore push to true to include the triggering element in the new window rather than the old. * @return a {@link Flux} of {@link Flux} windows, bounded depending * on the predicate. */ public final Flux> windowUntil(Predicate boundaryTrigger, boolean cutBefore) { return windowUntil(boundaryTrigger, cutBefore, Queues.SMALL_BUFFER_SIZE); } /** * Split this {@link Flux} sequence into multiple {@link Flux} windows delimited by the given * predicate and using a prefetch. A new window is opened each time the predicate * returns true. *

* If {@code cutBefore} is true, the old window will onComplete and the triggering * element will be emitted in the new window. Note it can mean that an empty window is * sometimes emitted, eg. if the first element in the sequence immediately matches the * predicate. *

* *

* Otherwise, the triggering element will be emitted in the old window before it does * onComplete, similar to {@link #windowUntil(Predicate)}. *

* * * @param boundaryTrigger a predicate that triggers the next window when it becomes true. * @param cutBefore push to true to include the triggering element in the new window rather than the old. * @param prefetch the request size to use for this {@link Flux}. * @return a {@link Flux} of {@link Flux} windows, bounded depending * on the predicate. */ public final Flux> windowUntil(Predicate boundaryTrigger, boolean cutBefore, int prefetch) { return onAssembly(new FluxWindowPredicate<>(this, Queues.unbounded(prefetch), Queues.unbounded(prefetch), prefetch, boundaryTrigger, cutBefore ? FluxBufferPredicate.Mode.UNTIL_CUT_BEFORE : FluxBufferPredicate.Mode.UNTIL)); } /** * Split this {@link Flux} sequence into multiple {@link Flux} windows that stay open * while a given predicate matches the source elements. Once the predicate returns * false, the window closes with an onComplete and the triggering element is discarded. *

* Note that for a sequence starting with a separator, or having several subsequent * separators anywhere in the sequence, each occurrence will lead to an empty window. * *

* * * @param inclusionPredicate a predicate that triggers the next window when it becomes false. * @return a {@link Flux} of {@link Flux} windows, each containing * subsequent elements that all passed a predicate. */ public final Flux> windowWhile(Predicate inclusionPredicate) { return windowWhile(inclusionPredicate, Queues.SMALL_BUFFER_SIZE); } /** * Split this {@link Flux} sequence into multiple {@link Flux} windows that stay open * while a given predicate matches the source elements. Once the predicate returns * false, the window closes with an onComplete and the triggering element is discarded. *

* Note that for a sequence starting with a separator, or having several subsequent * separators anywhere in the sequence, each occurrence will lead to an empty window. * *

* * * @param inclusionPredicate a predicate that triggers the next window when it becomes false. * @param prefetch the request size to use for this {@link Flux}. * @return a {@link Flux} of {@link Flux} windows, each containing * subsequent elements that all passed a predicate. */ public final Flux> windowWhile(Predicate inclusionPredicate, int prefetch) { return onAssembly(new FluxWindowPredicate<>(this, Queues.unbounded(prefetch), Queues.unbounded(prefetch), prefetch, inclusionPredicate, FluxBufferPredicate.Mode.WHILE)); } /** * Split this {@link Flux} sequence into potentially overlapping windows controlled by items of a * start {@link Publisher} and end {@link Publisher} derived from the start values. * *

* When Open signal is strictly not overlapping Close signal : dropping windows *

* *

* When Open signal is strictly more frequent than Close signal : overlapping windows *

* *

* When Open signal is exactly coordinated with Close signal : exact windows *

* * * @param bucketOpening a {@link Publisher} that opens a new window when it emits any item * @param closeSelector a {@link Function} given an opening signal and returning a {@link Publisher} that * will close the window when emitting * * @param the type of the sequence opening windows * @param the type of the sequence closing windows opened by the bucketOpening Publisher's elements * * @return a {@link Flux} of {@link Flux} windows opened by signals from a first * {@link Publisher} and lasting until a selected second {@link Publisher} emits */ public final Flux> windowWhen(Publisher bucketOpening, final Function> closeSelector) { return onAssembly(new FluxWindowWhen<>(this, bucketOpening, closeSelector, Queues.unbounded(Queues.XS_BUFFER_SIZE), Queues.unbounded(Queues.XS_BUFFER_SIZE))); } /** * Combine the most recently emitted values from both this {@link Flux} and another * {@link Publisher} through a {@link BiFunction} and emits the result. *

* The operator will drop values from this {@link Flux} until the other * {@link Publisher} produces any value. *

* If the other {@link Publisher} completes without any value, the sequence is completed. * *

* * * @param other the {@link Publisher} to combine with * @param resultSelector the bi-function called with each pair of source and other * elements that should return a single value to be emitted * * @param the other {@link Publisher} sequence type * @param the result type * * @return a combined {@link Flux} gated by another {@link Publisher} */ public final Flux withLatestFrom(Publisher other, BiFunction resultSelector){ return onAssembly(new FluxWithLatestFrom<>(this, other, resultSelector)); } /** * Zip this {@link Flux} with another {@link Publisher} source, that is to say wait * for both to emit one element and combine these elements once into a {@link Tuple2}. * The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. *

* *

* @param source2 The second source {@link Publisher} to zip with this {@link Flux}. * @param type of the value from source2 * * @return a zipped {@link Flux} * */ public final Flux> zipWith(Publisher source2) { return zipWith(source2, tuple2Function()); } /** * Zip this {@link Flux} with another {@link Publisher} source, that is to say wait * for both to emit one element and combine these elements using a {@code combinator} * {@link BiFunction} * The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. *

* *

* @param source2 The second source {@link Publisher} to zip with this {@link Flux}. * @param combinator The aggregate function that will receive a unique value from each * source and return the value to signal downstream * @param type of the value from source2 * @param The produced output after transformation by the combinator * * @return a zipped {@link Flux} */ public final Flux zipWith(Publisher source2, final BiFunction combinator) { if (this instanceof FluxZip) { @SuppressWarnings("unchecked") FluxZip o = (FluxZip) this; Flux result = o.zipAdditionalSource(source2, combinator); if (result != null) { return result; } } return zip(this, source2, combinator); } /** * Zip this {@link Flux} with another {@link Publisher} source, that is to say wait * for both to emit one element and combine these elements using a {@code combinator} * {@link BiFunction} * The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. *

* *

* @param source2 The second source {@link Publisher} to zip with this {@link Flux}. * @param prefetch the request size to use for this {@link Flux} and the other {@link Publisher} * @param combinator The aggregate function that will receive a unique value from each * source and return the value to signal downstream * @param type of the value from source2 * @param The produced output after transformation by the combinator * * @return a zipped {@link Flux} */ @SuppressWarnings("unchecked") public final Flux zipWith(Publisher source2, int prefetch, BiFunction combinator) { return zip(objects -> combinator.apply((T) objects[0], (T2) objects[1]), prefetch, this, source2); } /** * Zip this {@link Flux} with another {@link Publisher} source, that is to say wait * for both to emit one element and combine these elements once into a {@link Tuple2}. * The operator will continue doing so until any of the sources completes. * Errors will immediately be forwarded. * This "Step-Merge" processing is especially useful in Scatter-Gather scenarios. * *

* *

* @param source2 The second source {@link Publisher} to zip with this {@link Flux}. * @param prefetch the request size to use for this {@link Flux} and the other {@link Publisher} * @param type of the value from source2 * * @return a zipped {@link Flux} */ public final Flux> zipWith(Publisher source2, int prefetch) { return zipWith(source2, prefetch, tuple2Function()); } /** * Zip elements from this {@link Flux} with the content of an {@link Iterable}, that is * to say combine one element from each, pairwise, into a {@link Tuple2}. * *

* * * @param iterable the {@link Iterable} to zip with * @param the value type of the other iterable sequence * * @return a zipped {@link Flux} * */ @SuppressWarnings("unchecked") public final Flux> zipWithIterable(Iterable iterable) { return zipWithIterable(iterable, tuple2Function()); } /** * Zip elements from this {@link Flux} with the content of an {@link Iterable}, that is * to say combine one element from each, pairwise, using the given zipper {@link BiFunction}. * * *

* * * @param accumulator the reducing {@link BiFunction} * @param initial the seed, the initial leftmost argument to pass to the reducing {@link BiFunction} * @param the type of the seed and the reduced object * * @return a reduced {@link Flux} * */ public final Mono reduce(A initial, BiFunction accumulator) { return reduceWith(() -> initial, accumulator); } /** * Reduce the values from this {@link Flux} sequence into an single object matching the * type of a lazily supplied seed value. Reduction is performed using a * {@link BiFunction} that takes the intermediate result of the reduction and the * current value and returns the next intermediate value of the reduction. First * element is paired with the seed value, supplied via {@literal initial}. * *

* * * @param iterable the {@link Iterable} to zip with * @param zipper the {@link BiFunction} pair combinator * * @param the value type of the other iterable sequence * @param the result type * * @return a zipped {@link Flux} * */ public final Flux zipWithIterable(Iterable iterable, BiFunction zipper) { return onAssembly(new FluxZipIterable<>(this, iterable, zipper)); } /** * To be used by custom operators: invokes assembly {@link Hooks} pointcut given a * {@link Flux}, potentially returning a new {@link Flux}. This is for example useful * to activate cross-cutting concerns at assembly time, eg. a generalized * {@link #checkpoint()}. * * @param the value type * @param source the source to apply assembly hooks onto * * @return the source, potentially wrapped with assembly time cross-cutting behavior */ @SuppressWarnings("unchecked") protected static Flux onAssembly(Flux source) { Function hook = Hooks.onEachOperatorHook; if(hook == null) { return source; } return (Flux)hook.apply(source); } /** * To be used by custom operators: invokes assembly {@link Hooks} pointcut given a * {@link Flux}, potentially returning a new {@link Flux}. This is for example useful * to activate cross-cutting concerns at assembly time, eg. a generalized * {@link #checkpoint()}. * * @param the value type * @param source the source to apply assembly hooks onto * * @return the source, potentially wrapped with assembly time cross-cutting behavior */ @SuppressWarnings("unchecked") protected static Flux onLastAssembly(Flux source) { Function hook = Hooks.onLastOperatorHook; if(hook == null) { return source; } return (Flux)Objects.requireNonNull(hook.apply(source), "LastOperator hook returned null"); } /** * To be used by custom operators: invokes assembly {@link Hooks} pointcut given a * {@link ConnectableFlux}, potentially returning a new {@link ConnectableFlux}. This * is for example useful to activate cross-cutting concerns at assembly time, eg. a * generalized {@link #checkpoint()}. * * @param the value type * @param source the source to apply assembly hooks onto * * @return the source, potentially wrapped with assembly time cross-cutting behavior */ @SuppressWarnings("unchecked") protected static ConnectableFlux onAssembly(ConnectableFlux source) { Function hook = Hooks.onEachOperatorHook; if(hook == null) { return source; } return (ConnectableFlux)hook.apply(source); } @Override public String toString() { return getClass().getSimpleName(); } final Flux flatMap(Function> mapper, boolean delayError, int concurrency, int prefetch) { return onAssembly(new FluxFlatMap<>( this, mapper, delayError, concurrency, Queues.get(concurrency), prefetch, Queues.get(prefetch) )); } final Flux flatMapSequential(Function> mapper, boolean delayError, int maxConcurrency, int prefetch) { return onAssembly(new FluxMergeSequential<>(this, mapper, maxConcurrency, prefetch, delayError ? FluxConcatMap.ErrorMode.END : FluxConcatMap.ErrorMode.IMMEDIATE)); } @SuppressWarnings("unchecked") static Flux doOnSignal(Flux source, @Nullable Consumer onSubscribe, @Nullable Consumer onNext, @Nullable Consumer onError, @Nullable Runnable onComplete, @Nullable Runnable onAfterTerminate, @Nullable LongConsumer onRequest, @Nullable Runnable onCancel) { if (source instanceof Fuseable) { return onAssembly(new FluxPeekFuseable<>(source, onSubscribe, onNext, onError, onComplete, onAfterTerminate, onRequest, onCancel)); } return onAssembly(new FluxPeek<>(source, onSubscribe, onNext, onError, onComplete, onAfterTerminate, onRequest, onCancel)); } /** * Returns the appropriate Mono instance for a known Supplier Flux. * * @param supplier the supplier Flux * * @return the mono representing that Flux */ static Mono convertToMono(Callable supplier) { if (supplier instanceof Fuseable.ScalarCallable) { Fuseable.ScalarCallable scalarCallable = (Fuseable.ScalarCallable) supplier; T v; try { v = scalarCallable.call(); } catch (Exception e) { return Mono.error(e); } if (v == null) { return Mono.empty(); } return Mono.just(v); } return Mono.onAssembly(new MonoCallable<>(supplier)); } @SafeVarargs static Flux merge(int prefetch, boolean delayError, Publisher... sources) { if (sources.length == 0) { return empty(); } if (sources.length == 1) { return from(sources[0]); } return onAssembly(new FluxMerge<>(sources, delayError, sources.length, Queues.get(sources.length), prefetch, Queues.get(prefetch))); } @SafeVarargs static Flux mergeSequential(int prefetch, boolean delayError, Publisher... sources) { if (sources.length == 0) { return empty(); } if (sources.length == 1) { return from(sources[0]); } return onAssembly(new FluxMergeSequential<>(new FluxArray<>(sources), identityFunction(), sources.length, prefetch, delayError ? FluxConcatMap.ErrorMode.END : FluxConcatMap.ErrorMode.IMMEDIATE)); } static Flux mergeSequential(Publisher> sources, boolean delayError, int maxConcurrency, int prefetch) { return onAssembly(new FluxMergeSequential<>(from(sources), identityFunction(), maxConcurrency, prefetch, delayError ? FluxConcatMap.ErrorMode.END : FluxConcatMap.ErrorMode.IMMEDIATE)); } static Flux mergeSequential(Iterable> sources, boolean delayError, int maxConcurrency, int prefetch) { return onAssembly(new FluxMergeSequential<>(new FluxIterable<>(sources), identityFunction(), maxConcurrency, prefetch, delayError ? FluxConcatMap.ErrorMode.END : FluxConcatMap.ErrorMode.IMMEDIATE)); } static BooleanSupplier countingBooleanSupplier(BooleanSupplier predicate, long max) { if (max <= 0) { return predicate; } return new BooleanSupplier() { long n; @Override public boolean getAsBoolean() { return n++ < max && predicate.getAsBoolean(); } }; } static Predicate countingPredicate(Predicate predicate, long max) { if (max == 0) { return predicate; } return new Predicate() { long n; @Override public boolean test(O o) { return n++ < max && predicate.test(o); } }; } @SuppressWarnings("unchecked") static Supplier> hashSetSupplier() { return SET_SUPPLIER; } @SuppressWarnings("unchecked") static Supplier> listSupplier() { return LIST_SUPPLIER; } @SuppressWarnings("unchecked") static Function hashcodeSupplier() { return HASHCODE_EXTRACTOR; } @SuppressWarnings("unchecked") static BiPredicate equalPredicate() { return OBJECT_EQUAL; } @SuppressWarnings("unchecked") static Function identityFunction(){ return IDENTITY_FUNCTION; } @SuppressWarnings("unchecked") static BiFunction> tuple2Function() { return TUPLE2_BIFUNCTION; } /** * Unchecked wrap of {@link Publisher} as {@link Flux}, supporting {@link Fuseable} sources * * @param source the {@link Publisher} to wrap * @param input upstream type * @return a wrapped {@link Flux} */ @SuppressWarnings("unchecked") static Flux wrap(Publisher source){ if(source instanceof Mono){ if(source instanceof Fuseable){ return new FluxSourceMonoFuseable<>((Mono)source); } return new FluxSourceMono<>((Mono)source); } if(source instanceof Fuseable){ return new FluxSourceFuseable<>(source); } return new FluxSource<>(source); } @SuppressWarnings("rawtypes") static final BiFunction TUPLE2_BIFUNCTION = Tuples::of; @SuppressWarnings("rawtypes") static final Supplier LIST_SUPPLIER = ArrayList::new; @SuppressWarnings("rawtypes") static final Supplier SET_SUPPLIER = HashSet::new; static final BooleanSupplier ALWAYS_BOOLEAN_SUPPLIER = () -> true; @SuppressWarnings("rawtypes") static final Function HASHCODE_EXTRACTOR = Object::hashCode; static final BiPredicate OBJECT_EQUAL = Object::equals; @SuppressWarnings("rawtypes") static final Function IDENTITY_FUNCTION = Function.identity(); }