Skip to content

Commit 8068404

Browse files
authored
2.x: Improve the JavaDoc of the other lift() operators (#5865)
1 parent 5f45255 commit 8068404

File tree

5 files changed

+529
-54
lines changed

5 files changed

+529
-54
lines changed

src/main/java/io/reactivex/Completable.java

+122-5
Original file line numberDiff line numberDiff line change
@@ -1369,15 +1369,132 @@ public final Completable doFinally(Action onFinally) {
13691369
}
13701370

13711371
/**
1372-
* <strong>Advanced use without safeguards:</strong> lifts a CompletableOperator
1373-
* transformation into the chain of Completables.
1372+
* <strong>This method requires advanced knowledge about building operators, please consider
1373+
* other standard composition methods first;</strong>
1374+
* Returns a {@code Completable} which, when subscribed to, invokes the {@link CompletableOperator#apply(CompletableObserver) apply(CompletableObserver)} method
1375+
* of the provided {@link CompletableOperator} for each individual downstream {@link Completable} and allows the
1376+
* insertion of a custom operator by accessing the downstream's {@link CompletableObserver} during this subscription phase
1377+
* and providing a new {@code CompletableObserver}, containing the custom operator's intended business logic, that will be
1378+
* used in the subscription process going further upstream.
1379+
* <p>
1380+
* Generally, such a new {@code CompletableObserver} will wrap the downstream's {@code CompletableObserver} and forwards the
1381+
* {@code onError} and {@code onComplete} events from the upstream directly or according to the
1382+
* emission pattern the custom operator's business logic requires. In addition, such operator can intercept the
1383+
* flow control calls of {@code dispose} and {@code isDisposed} that would have traveled upstream and perform
1384+
* additional actions depending on the same business logic requirements.
1385+
* <p>
1386+
* Example:
1387+
* <pre><code>
1388+
* // Step 1: Create the consumer type that will be returned by the CompletableOperator.apply():
1389+
*
1390+
* public final class CustomCompletableObserver implements CompletableObserver, Disposable {
1391+
*
1392+
* // The donstream's CompletableObserver that will receive the onXXX events
1393+
* final CompletableObserver downstream;
1394+
*
1395+
* // The connection to the upstream source that will call this class' onXXX methods
1396+
* Disposable upstream;
1397+
*
1398+
* // The constructor takes the downstream subscriber and usually any other parameters
1399+
* public CustomCompletableObserver(CompletableObserver downstream) {
1400+
* this.downstream = downstream;
1401+
* }
1402+
*
1403+
* // In the subscription phase, the upstream sends a Disposable to this class
1404+
* // and subsequently this class has to send a Disposable to the downstream.
1405+
* // Note that relaying the upstream's Disposable directly is not allowed in RxJava
1406+
* &#64;Override
1407+
* public void onSubscribe(Disposable s) {
1408+
* if (upstream != null) {
1409+
* s.cancel();
1410+
* } else {
1411+
* upstream = s;
1412+
* downstream.onSubscribe(this);
1413+
* }
1414+
* }
1415+
*
1416+
* // Some operators may handle the upstream's error while others
1417+
* // could just forward it to the downstream.
1418+
* &#64;Override
1419+
* public void onError(Throwable throwable) {
1420+
* downstream.onError(throwable);
1421+
* }
1422+
*
1423+
* // When the upstream completes, usually the downstream should complete as well.
1424+
* // In completable, this could also mean doing some side-effects
1425+
* &#64;Override
1426+
* public void onComplete() {
1427+
* System.out.println("Sequence completed");
1428+
* downstream.onComplete();
1429+
* }
1430+
*
1431+
* // Some operators may use their own resources which should be cleaned up if
1432+
* // the downstream disposes the flow before it completed. Operators without
1433+
* // resources can simply forward the dispose to the upstream.
1434+
* // In some cases, a disposed flag may be set by this method so that other parts
1435+
* // of this class may detect the dispose and stop sending events
1436+
* // to the downstream.
1437+
* &#64;Override
1438+
* public void dispose() {
1439+
* upstream.dispose();
1440+
* }
1441+
*
1442+
* // Some operators may simply forward the call to the upstream while others
1443+
* // can return the disposed flag set in dispose().
1444+
* &#64;Override
1445+
* public boolean isDisposed() {
1446+
* return upstream.isDisposed();
1447+
* }
1448+
* }
1449+
*
1450+
* // Step 2: Create a class that implements the CompletableOperator interface and
1451+
* // returns the custom consumer type from above in its apply() method.
1452+
* // Such class may define additional parameters to be submitted to
1453+
* // the custom consumer type.
1454+
*
1455+
* final class CustomCompletableOperator implements CompletableOperator {
1456+
* &#64;Override
1457+
* public CompletableObserver apply(CompletableObserver upstream) {
1458+
* return new CustomCompletableObserver(upstream);
1459+
* }
1460+
* }
1461+
*
1462+
* // Step 3: Apply the custom operator via lift() in a flow by creating an instance of it
1463+
* // or reusing an existing one.
1464+
*
1465+
* Completable.complete()
1466+
* .lift(new CustomCompletableOperator())
1467+
* .test()
1468+
* .assertResult();
1469+
* </code></pre>
1470+
* <p>
1471+
* Creating custom operators can be complicated and it is recommended one consults the
1472+
* <a href="https://github.com/ReactiveX/RxJava/wiki/Writing-operators-for-2.0">RxJava wiki: Writing operators</a> page about
1473+
* the tools, requirements, rules, considerations and pitfalls of implementing them.
1474+
* <p>
1475+
* Note that implementing custom operators via this {@code lift()} method adds slightly more overhead by requiring
1476+
* an additional allocation and indirection per assembled flows. Instead, extending the abstract {@code Completable}
1477+
* class and creating a {@link CompletableTransformer} with it is recommended.
1478+
* <p>
1479+
* Note also that it is not possible to stop the subscription phase in {@code lift()} as the {@code apply()} method
1480+
* requires a non-null {@code CompletableObserver} instance to be returned, which is then unconditionally subscribed to
1481+
* the upstream {@code Completable}. For example, if the operator decided there is no reason to subscribe to the
1482+
* upstream source because of some optimization possibility or a failure to prepare the operator, it still has to
1483+
* return a {@code CompletableObserver} that should immediately dispose the upstream's {@code Disposable} in its
1484+
* {@code onSubscribe} method. Again, using a {@code CompletableTransformer} and extending the {@code Completable} is
1485+
* a better option as {@link #subscribeActual} can decide to not subscribe to its upstream after all.
13741486
* <dl>
13751487
* <dt><b>Scheduler:</b></dt>
1376-
* <dd>{@code lift} does not operate by default on a particular {@link Scheduler}.</dd>
1488+
* <dd>{@code lift} does not operate by default on a particular {@link Scheduler}, however, the
1489+
* {@link CompletableOperator} may use a {@code Scheduler} to support its own asynchronous behavior.</dd>
13771490
* </dl>
1378-
* @param onLift the lifting function that transforms the child subscriber with a parent subscriber.
1491+
*
1492+
* @param onLift the {@link CompletableOperator} that receives the downstream's {@code CompletableObserver} and should return
1493+
* a {@code CompletableObserver} with custom behavior to be used as the consumer for the current
1494+
* {@code Completable}.
13791495
* @return the new Completable instance
1380-
* @throws NullPointerException if onLift is null
1496+
* @see <a href="https://github.com/ReactiveX/RxJava/wiki/Writing-operators-for-2.0">RxJava wiki: Writing operators</a>
1497+
* @see #compose(CompletableTransformer)
13811498
*/
13821499
@CheckReturnValue
13831500
@SchedulerSupport(SchedulerSupport.NONE)

src/main/java/io/reactivex/Flowable.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -10068,13 +10068,13 @@ public final Single<T> lastOrError() {
1006810068
* Returns a {@code Flowable} which, when subscribed to, invokes the {@link FlowableOperator#apply(Subscriber) apply(Subscriber)} method
1006910069
* of the provided {@link FlowableOperator} for each individual downstream {@link Subscriber} and allows the
1007010070
* insertion of a custom operator by accessing the downstream's {@link Subscriber} during this subscription phase
10071-
* and providing a new {@code Subscriber}, containing the custom operator's intended business logic, that will be
10071+
* and providing a new {@code Subscriber}, containing the custom operator's intended business logic, that will be
1007210072
* used in the subscription process going further upstream.
1007310073
* <p>
1007410074
* Generally, such a new {@code Subscriber} will wrap the downstream's {@code Subscriber} and forwards the
1007510075
* {@code onNext}, {@code onError} and {@code onComplete} events from the upstream directly or according to the
10076-
* emission pattern the custom operator's business logic requires. In addition, such operator can intercept the
10077-
* flow control calls of {@code cancel} and {@code request} that would have travelled upstream and perform
10076+
* emission pattern the custom operator's business logic requires. In addition, such operator can intercept the
10077+
* flow control calls of {@code cancel} and {@code request} that would have traveled upstream and perform
1007810078
* additional actions depending on the same business logic requirements.
1007910079
* <p>
1008010080
* Example:
@@ -10192,7 +10192,7 @@ public final Single<T> lastOrError() {
1019210192
* a better option as {@link #subscribeActual} can decide to not subscribe to its upstream after all.
1019310193
* <dl>
1019410194
* <dt><b>Backpressure:</b></dt>
10195-
* <dd>The {@code Subscriber} instance returned by the {@link FlowableOperator} is responsible to be
10195+
* <dd>The {@code Subscriber} instance returned by the {@link FlowableOperator} is responsible to be
1019610196
* backpressure-aware or document the fact that the consumer of the returned {@code Publisher} has to apply one of
1019710197
* the {@code onBackpressureXXX} operators.</dd>
1019810198
* <dt><b>Scheduler:</b></dt>

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

+139-15
Original file line numberDiff line numberDiff line change
@@ -3110,27 +3110,151 @@ public final Single<Boolean> isEmpty() {
31103110
}
31113111

31123112
/**
3113-
* Lifts a function to the current Maybe and returns a new Maybe that when subscribed to will pass the
3114-
* values of the current Maybe through the MaybeOperator function.
3113+
* <strong>This method requires advanced knowledge about building operators, please consider
3114+
* other standard composition methods first;</strong>
3115+
* Returns a {@code Maybe} which, when subscribed to, invokes the {@link MaybeOperator#apply(MaybeObserver) apply(MaybeObserver)} method
3116+
* of the provided {@link MaybeOperator} for each individual downstream {@link Maybe} and allows the
3117+
* insertion of a custom operator by accessing the downstream's {@link MaybeObserver} during this subscription phase
3118+
* and providing a new {@code MaybeObserver}, containing the custom operator's intended business logic, that will be
3119+
* used in the subscription process going further upstream.
3120+
* <p>
3121+
* Generally, such a new {@code MaybeObserver} will wrap the downstream's {@code MaybeObserver} and forwards the
3122+
* {@code onSuccess}, {@code onError} and {@code onComplete} events from the upstream directly or according to the
3123+
* emission pattern the custom operator's business logic requires. In addition, such operator can intercept the
3124+
* flow control calls of {@code dispose} and {@code isDisposed} that would have traveled upstream and perform
3125+
* additional actions depending on the same business logic requirements.
31153126
* <p>
3116-
* In other words, this allows chaining TaskExecutors together on a Maybe for acting on the values within
3117-
* the Maybe.
3127+
* Example:
3128+
* <pre><code>
3129+
* // Step 1: Create the consumer type that will be returned by the MaybeOperator.apply():
3130+
*
3131+
* public final class CustomMaybeObserver&lt;T&gt; implements MaybeObserver&lt;T&gt;, Disposable {
3132+
*
3133+
* // The donstream's MaybeObserver that will receive the onXXX events
3134+
* final MaybeObserver&lt;? super String&gt; downstream;
3135+
*
3136+
* // The connection to the upstream source that will call this class' onXXX methods
3137+
* Disposable upstream;
3138+
*
3139+
* // The constructor takes the downstream subscriber and usually any other parameters
3140+
* public CustomMaybeObserver(MaybeObserver&lt;? super String&gt; downstream) {
3141+
* this.downstream = downstream;
3142+
* }
3143+
*
3144+
* // In the subscription phase, the upstream sends a Disposable to this class
3145+
* // and subsequently this class has to send a Disposable to the downstream.
3146+
* // Note that relaying the upstream's Disposable directly is not allowed in RxJava
3147+
* &#64;Override
3148+
* public void onSubscribe(Disposable s) {
3149+
* if (upstream != null) {
3150+
* s.cancel();
3151+
* } else {
3152+
* upstream = s;
3153+
* downstream.onSubscribe(this);
3154+
* }
3155+
* }
3156+
*
3157+
* // The upstream calls this with the next item and the implementation's
3158+
* // responsibility is to emit an item to the downstream based on the intended
3159+
* // business logic, or if it can't do so for the particular item,
3160+
* // request more from the upstream
3161+
* &#64;Override
3162+
* public void onSuccess(T item) {
3163+
* String str = item.toString();
3164+
* if (str.length() &lt; 2) {
3165+
* downstream.onSuccess(str);
3166+
* } else {
3167+
* // Maybe is usually expected to produce one of the onXXX events
3168+
* downstream.onComplete();
3169+
* }
3170+
* }
3171+
*
3172+
* // Some operators may handle the upstream's error while others
3173+
* // could just forward it to the downstream.
3174+
* &#64;Override
3175+
* public void onError(Throwable throwable) {
3176+
* downstream.onError(throwable);
3177+
* }
3178+
*
3179+
* // When the upstream completes, usually the downstream should complete as well.
3180+
* &#64;Override
3181+
* public void onComplete() {
3182+
* downstream.onComplete();
3183+
* }
3184+
*
3185+
* // Some operators may use their own resources which should be cleaned up if
3186+
* // the downstream disposes the flow before it completed. Operators without
3187+
* // resources can simply forward the dispose to the upstream.
3188+
* // In some cases, a disposed flag may be set by this method so that other parts
3189+
* // of this class may detect the dispose and stop sending events
3190+
* // to the downstream.
3191+
* &#64;Override
3192+
* public void dispose() {
3193+
* upstream.dispose();
3194+
* }
3195+
*
3196+
* // Some operators may simply forward the call to the upstream while others
3197+
* // can return the disposed flag set in dispose().
3198+
* &#64;Override
3199+
* public boolean isDisposed() {
3200+
* return upstream.isDisposed();
3201+
* }
3202+
* }
3203+
*
3204+
* // Step 2: Create a class that implements the MaybeOperator interface and
3205+
* // returns the custom consumer type from above in its apply() method.
3206+
* // Such class may define additional parameters to be submitted to
3207+
* // the custom consumer type.
3208+
*
3209+
* final class CustomMaybeOperator&lt;T&gt; implements MaybeOperator&lt;String&gt; {
3210+
* &#64;Override
3211+
* public MaybeObserver&lt;? super String&gt; apply(MaybeObserver&lt;? super T&gt; upstream) {
3212+
* return new CustomMaybeObserver&lt;T&gt;(upstream);
3213+
* }
3214+
* }
3215+
*
3216+
* // Step 3: Apply the custom operator via lift() in a flow by creating an instance of it
3217+
* // or reusing an existing one.
3218+
*
3219+
* Maybe.just(5)
3220+
* .lift(new CustomMaybeOperator&lt;Integer&gt;())
3221+
* .test()
3222+
* .assertResult("5");
3223+
*
3224+
* Maybe.just(15)
3225+
* .lift(new CustomMaybeOperator&lt;Integer&gt;())
3226+
* .test()
3227+
* .assertResult();
3228+
* </code></pre>
3229+
* <p>
3230+
* Creating custom operators can be complicated and it is recommended one consults the
3231+
* <a href="https://github.com/ReactiveX/RxJava/wiki/Writing-operators-for-2.0">RxJava wiki: Writing operators</a> page about
3232+
* the tools, requirements, rules, considerations and pitfalls of implementing them.
31183233
* <p>
3119-
* {@code task.map(...).filter(...).lift(new OperatorA()).lift(new OperatorB(...)).subscribe() }
3234+
* Note that implementing custom operators via this {@code lift()} method adds slightly more overhead by requiring
3235+
* an additional allocation and indirection per assembled flows. Instead, extending the abstract {@code Maybe}
3236+
* class and creating a {@link MaybeTransformer} with it is recommended.
31203237
* <p>
3121-
* If the operator you are creating is designed to act on the item emitted by a source Maybe, use
3122-
* {@code lift}. If your operator is designed to transform the source Maybe as a whole (for instance, by
3123-
* applying a particular set of existing RxJava operators to it) use {@link #compose}.
3238+
* Note also that it is not possible to stop the subscription phase in {@code lift()} as the {@code apply()} method
3239+
* requires a non-null {@code MaybeObserver} instance to be returned, which is then unconditionally subscribed to
3240+
* the upstream {@code Maybe}. For example, if the operator decided there is no reason to subscribe to the
3241+
* upstream source because of some optimization possibility or a failure to prepare the operator, it still has to
3242+
* return a {@code MaybeObserver} that should immediately dispose the upstream's {@code Disposable} in its
3243+
* {@code onSubscribe} method. Again, using a {@code MaybeTransformer} and extending the {@code Maybe} is
3244+
* a better option as {@link #subscribeActual} can decide to not subscribe to its upstream after all.
31243245
* <dl>
3125-
* <dt><b>Scheduler:</b></dt>
3126-
* <dd>{@code lift} does not operate by default on a particular {@link Scheduler}.</dd>
3246+
* <dt><b>Scheduler:</b></dt>
3247+
* <dd>{@code lift} does not operate by default on a particular {@link Scheduler}, however, the
3248+
* {@link MaybeOperator} may use a {@code Scheduler} to support its own asynchronous behavior.</dd>
31273249
* </dl>
31283250
*
3129-
* @param <R> the downstream's value type (output)
3130-
* @param lift
3131-
* the MaybeOperator that implements the Maybe-operating function to be applied to the source Maybe
3132-
* @return a Maybe that is the result of applying the lifted Operator to the source Maybe
3133-
* @see <a href="https://github.com/ReactiveX/RxJava/wiki/Implementing-Your-Own-Operators">RxJava wiki: Implementing Your Own Operators</a>
3251+
* @param <R> the output value type
3252+
* @param lift the {@link MaybeOperator} that receives the downstream's {@code MaybeObserver} and should return
3253+
* a {@code MaybeObserver} with custom behavior to be used as the consumer for the current
3254+
* {@code Maybe}.
3255+
* @return the new Maybe instance
3256+
* @see <a href="https://github.com/ReactiveX/RxJava/wiki/Writing-operators-for-2.0">RxJava wiki: Writing operators</a>
3257+
* @see #compose(MaybeTransformer)
31343258
*/
31353259
@CheckReturnValue
31363260
@SchedulerSupport(SchedulerSupport.NONE)

0 commit comments

Comments
 (0)