Skip to content

Commit 34f381c

Browse files
authored
3.x: [Java 8] Add flattenStreamAsX to Maybe/Single (ReactiveX#6805)
* 3.x: [Java 8] Add flattenStreamAsX to Maybe/Single * Add RS TCK tests for flattenStreamAsFlowable
1 parent 79f8e6d commit 34f381c

15 files changed

+2647
-7
lines changed

src/main/java/io/reactivex/rxjava3/core/Maybe.java

+85
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import java.util.*;
1717
import java.util.concurrent.*;
18+
import java.util.stream.*;
1819

1920
import org.reactivestreams.*;
2021

@@ -3152,6 +3153,7 @@ public final <U, R> Maybe<R> flatMap(@NonNull Function<? super T, ? extends Mayb
31523153
* source Maybe
31533154
* @return the new Flowable instance
31543155
* @see <a href="http://reactivex.io/documentation/operators/flatmap.html">ReactiveX operators documentation: FlatMap</a>
3156+
* @see #flattenStreamAsFlowable(Function)
31553157
*/
31563158
@BackpressureSupport(BackpressureKind.FULL)
31573159
@CheckReturnValue
@@ -5004,4 +5006,87 @@ public final CompletionStage<T> toCompletionStage() {
50045006
public final CompletionStage<T> toCompletionStage(@Nullable T defaultItem) {
50055007
return subscribeWith(new CompletionStageConsumer<>(true, defaultItem));
50065008
}
5009+
5010+
/**
5011+
* Maps the upstream succecss value into a Java {@link Stream} and emits its
5012+
* items to the downstream consumer as a {@link Flowable}.
5013+
* <p>
5014+
* <img width="640" height="247" src="https://raw.github.com/wiki/ReactiveX/RxJava/images/rx-operators/flattenStreamAsFlowable.m.png" alt="">
5015+
* <p>
5016+
* The operator closes the {@code Stream} upon cancellation and when it terminates. Exceptions raised when
5017+
* closing a {@code Stream} are routed to the global error handler ({@link RxJavaPlugins#onError(Throwable)}.
5018+
* If a {@code Stream} should not be closed, turn it into an {@link Iterable} and use {@link #flattenAsFlowable(Function)}:
5019+
* <pre><code>
5020+
* source.flattenAsFlowable(item -&gt; createStream(item)::iterator);
5021+
* </code></pre>
5022+
* <p>
5023+
* Primitive streams are not supported and items have to be boxed manually (e.g., via {@link IntStream#boxed()}):
5024+
* <pre><code>
5025+
* source.flattenStreamAsFlowable(item -&gt; IntStream.rangeClosed(1, 10).boxed());
5026+
* </code></pre>
5027+
* <p>
5028+
* {@code Stream} does not support concurrent usage so creating and/or consuming the same instance multiple times
5029+
* from multiple threads can lead to undefined behavior.
5030+
* <dl>
5031+
* <dt><b>Backpressure:</b></dt>
5032+
* <dd>The operator honors backpressure from downstream and iterates the given {@code Stream}
5033+
* on demand (i.e., when requested).</dd>
5034+
* <dt><b>Scheduler:</b></dt>
5035+
* <dd>{@code flattenStreamAsFlowable} does not operate by default on a particular {@link Scheduler}.</dd>
5036+
* </dl>
5037+
* @param <R> the element type of the {@code Stream} and the output {@code Flowable}
5038+
* @param mapper the function that receives the upstream success item and should
5039+
* return a {@code Stream} of values to emit.
5040+
* @return the new Flowable instance
5041+
* @since 3.0.0
5042+
* @see #flattenAsFlowable(Function)
5043+
* @see #flattenStreamAsObservable(Function)
5044+
*/
5045+
@CheckReturnValue
5046+
@SchedulerSupport(SchedulerSupport.NONE)
5047+
@BackpressureSupport(BackpressureKind.FULL)
5048+
@NonNull
5049+
public final <R> Flowable<R> flattenStreamAsFlowable(@NonNull Function<? super T, ? extends Stream<? extends R>> mapper) {
5050+
Objects.requireNonNull(mapper, "mapper is null");
5051+
return RxJavaPlugins.onAssembly(new MaybeFlattenStreamAsFlowable<>(this, mapper));
5052+
}
5053+
5054+
/**
5055+
* Maps the upstream succecss value into a Java {@link Stream} and emits its
5056+
* items to the downstream consumer as an {@link Observable}.
5057+
* <img width="640" height="247" src="https://raw.github.com/wiki/ReactiveX/RxJava/images/rx-operators/flattenStreamAsObservable.m.png" alt="">
5058+
* <p>
5059+
* The operator closes the {@code Stream} upon cancellation and when it terminates. Exceptions raised when
5060+
* closing a {@code Stream} are routed to the global error handler ({@link RxJavaPlugins#onError(Throwable)}.
5061+
* If a {@code Stream} should not be closed, turn it into an {@link Iterable} and use {@link #flattenAsObservable(Function)}:
5062+
* <pre><code>
5063+
* source.flattenAsObservable(item -&gt; createStream(item)::iterator);
5064+
* </code></pre>
5065+
* <p>
5066+
* Primitive streams are not supported and items have to be boxed manually (e.g., via {@link IntStream#boxed()}):
5067+
* <pre><code>
5068+
* source.flattenStreamAsObservable(item -&gt; IntStream.rangeClosed(1, 10).boxed());
5069+
* </code></pre>
5070+
* <p>
5071+
* {@code Stream} does not support concurrent usage so creating and/or consuming the same instance multiple times
5072+
* from multiple threads can lead to undefined behavior.
5073+
* <dl>
5074+
* <dt><b>Scheduler:</b></dt>
5075+
* <dd>{@code flattenStreamAsObservable} does not operate by default on a particular {@link Scheduler}.</dd>
5076+
* </dl>
5077+
* @param <R> the element type of the {@code Stream} and the output {@code Observable}
5078+
* @param mapper the function that receives the upstream success item and should
5079+
* return a {@code Stream} of values to emit.
5080+
* @return the new Observable instance
5081+
* @since 3.0.0
5082+
* @see #flattenAsObservable(Function)
5083+
* @see #flattenStreamAsFlowable(Function)
5084+
*/
5085+
@CheckReturnValue
5086+
@SchedulerSupport(SchedulerSupport.NONE)
5087+
@NonNull
5088+
public final <R> Observable<R> flattenStreamAsObservable(@NonNull Function<? super T, ? extends Stream<? extends R>> mapper) {
5089+
Objects.requireNonNull(mapper, "mapper is null");
5090+
return RxJavaPlugins.onAssembly(new MaybeFlattenStreamAsObservable<>(this, mapper));
5091+
}
50075092
}

src/main/java/io/reactivex/rxjava3/core/Observable.java

+1
Original file line numberDiff line numberDiff line change
@@ -6517,6 +6517,7 @@ public final <R> Observable<R> concatMap(@NonNull Function<? super T, ? extends
65176517
* the scheduler where the {@code mapper} function will be executed
65186518
* @return an Observable that emits the result of applying the transformation function to each item emitted
65196519
* by the source ObservableSource and concatenating the ObservableSources obtained from this transformation
6520+
* @since 3.0.0
65206521
* @see <a href="http://reactivex.io/documentation/operators/flatmap.html">ReactiveX operators documentation: FlatMap</a>
65216522
*/
65226523
@CheckReturnValue

src/main/java/io/reactivex/rxjava3/core/Single.java

+87
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515

1616
import java.util.*;
1717
import java.util.concurrent.*;
18+
import java.util.stream.*;
1819

1920
import org.reactivestreams.Publisher;
2021

2122
import io.reactivex.rxjava3.annotations.*;
23+
import io.reactivex.rxjava3.core.Observable;
2224
import io.reactivex.rxjava3.disposables.Disposable;
2325
import io.reactivex.rxjava3.exceptions.Exceptions;
2426
import io.reactivex.rxjava3.functions.*;
@@ -2799,6 +2801,7 @@ public final <R> Flowable<R> flatMapPublisher(@NonNull Function<? super T, ? ext
27992801
* source Single
28002802
* @return the new Flowable instance
28012803
* @see <a href="http://reactivex.io/documentation/operators/flatmap.html">ReactiveX operators documentation: FlatMap</a>
2804+
* @see #flattenStreamAsFlowable(Function)
28022805
*/
28032806
@BackpressureSupport(BackpressureKind.FULL)
28042807
@CheckReturnValue
@@ -2826,6 +2829,7 @@ public final <U> Flowable<U> flattenAsFlowable(@NonNull Function<? super T, ? ex
28262829
* source Single
28272830
* @return the new Observable instance
28282831
* @see <a href="http://reactivex.io/documentation/operators/flatmap.html">ReactiveX operators documentation: FlatMap</a>
2832+
* @see #flattenStreamAsObservable(Function)
28292833
*/
28302834
@CheckReturnValue
28312835
@NonNull
@@ -4308,4 +4312,87 @@ private static <T> Single<T> toSingle(@NonNull Flowable<T> source) {
43084312
public final CompletionStage<T> toCompletionStage() {
43094313
return subscribeWith(new CompletionStageConsumer<>(false, null));
43104314
}
4315+
4316+
/**
4317+
* Maps the upstream succecss value into a Java {@link Stream} and emits its
4318+
* items to the downstream consumer as a {@link Flowable}.
4319+
* <img width="640" height="247" src="https://raw.github.com/wiki/ReactiveX/RxJava/images/rx-operators/flattenStreamAsFlowable.s.png" alt="">
4320+
* <p>
4321+
* The operator closes the {@code Stream} upon cancellation and when it terminates. Exceptions raised when
4322+
* closing a {@code Stream} are routed to the global error handler ({@link RxJavaPlugins#onError(Throwable)}.
4323+
* If a {@code Stream} should not be closed, turn it into an {@link Iterable} and use {@link #flattenAsFlowable(Function)}:
4324+
* <pre><code>
4325+
* source.flattenAsFlowable(item -&gt; createStream(item)::iterator);
4326+
* </code></pre>
4327+
* <p>
4328+
* Primitive streams are not supported and items have to be boxed manually (e.g., via {@link IntStream#boxed()}):
4329+
* <pre><code>
4330+
* source.flattenStreamAsFlowable(item -&gt; IntStream.rangeClosed(1, 10).boxed());
4331+
* </code></pre>
4332+
* <p>
4333+
* {@code Stream} does not support concurrent usage so creating and/or consuming the same instance multiple times
4334+
* from multiple threads can lead to undefined behavior.
4335+
* <dl>
4336+
* <dt><b>Backpressure:</b></dt>
4337+
* <dd>The operator honors backpressure from downstream and iterates the given {@code Stream}
4338+
* on demand (i.e., when requested).</dd>
4339+
* <dt><b>Scheduler:</b></dt>
4340+
* <dd>{@code flattenStreamAsFlowable} does not operate by default on a particular {@link Scheduler}.</dd>
4341+
* </dl>
4342+
* @param <R> the element type of the {@code Stream} and the output {@code Flowable}
4343+
* @param mapper the function that receives the upstream success item and should
4344+
* return a {@code Stream} of values to emit.
4345+
* @return the new Flowable instance
4346+
* @since 3.0.0
4347+
* @see #flattenAsFlowable(Function)
4348+
* @see #flattenStreamAsObservable(Function)
4349+
*/
4350+
@CheckReturnValue
4351+
@SchedulerSupport(SchedulerSupport.NONE)
4352+
@BackpressureSupport(BackpressureKind.FULL)
4353+
@NonNull
4354+
public final <R> Flowable<R> flattenStreamAsFlowable(@NonNull Function<? super T, ? extends Stream<? extends R>> mapper) {
4355+
Objects.requireNonNull(mapper, "mapper is null");
4356+
return RxJavaPlugins.onAssembly(new SingleFlattenStreamAsFlowable<>(this, mapper));
4357+
}
4358+
4359+
/**
4360+
* Maps the upstream succecss value into a Java {@link Stream} and emits its
4361+
* items to the downstream consumer as an {@link Observable}.
4362+
* <p>
4363+
* <img width="640" height="247" src="https://raw.github.com/wiki/ReactiveX/RxJava/images/rx-operators/flattenStreamAsObservable.s.png" alt="">
4364+
* <p>
4365+
* The operator closes the {@code Stream} upon cancellation and when it terminates. Exceptions raised when
4366+
* closing a {@code Stream} are routed to the global error handler ({@link RxJavaPlugins#onError(Throwable)}.
4367+
* If a {@code Stream} should not be closed, turn it into an {@link Iterable} and use {@link #flattenAsFlowable(Function)}:
4368+
* <pre><code>
4369+
* source.flattenAsObservable(item -&gt; createStream(item)::iterator);
4370+
* </code></pre>
4371+
* <p>
4372+
* Primitive streams are not supported and items have to be boxed manually (e.g., via {@link IntStream#boxed()}):
4373+
* <pre><code>
4374+
* source.flattenStreamAsObservable(item -&gt; IntStream.rangeClosed(1, 10).boxed());
4375+
* </code></pre>
4376+
* <p>
4377+
* {@code Stream} does not support concurrent usage so creating and/or consuming the same instance multiple times
4378+
* from multiple threads can lead to undefined behavior.
4379+
* <dl>
4380+
* <dt><b>Scheduler:</b></dt>
4381+
* <dd>{@code flattenStreamAsObservable} does not operate by default on a particular {@link Scheduler}.</dd>
4382+
* </dl>
4383+
* @param <R> the element type of the {@code Stream} and the output {@code Observable}
4384+
* @param mapper the function that receives the upstream success item and should
4385+
* return a {@code Stream} of values to emit.
4386+
* @return the new Observable instance
4387+
* @since 3.0.0
4388+
* @see #flattenAsObservable(Function)
4389+
* @see #flattenStreamAsFlowable(Function)
4390+
*/
4391+
@CheckReturnValue
4392+
@SchedulerSupport(SchedulerSupport.NONE)
4393+
@NonNull
4394+
public final <R> Observable<R> flattenStreamAsObservable(@NonNull Function<? super T, ? extends Stream<? extends R>> mapper) {
4395+
Objects.requireNonNull(mapper, "mapper is null");
4396+
return RxJavaPlugins.onAssembly(new SingleFlattenStreamAsObservable<>(this, mapper));
4397+
}
43114398
}

0 commit comments

Comments
 (0)