Skip to content

Commit af17c6e

Browse files
authored
3.x: [Java 8] Add Observable operators + cleanup (#6797)
1 parent 480889c commit af17c6e

38 files changed

+4854
-218
lines changed

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

+505-4
Large diffs are not rendered by default.

src/main/java/io/reactivex/rxjava3/internal/jdk8/FlowableFromStream.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public static <T> void subscribeStream(Subscriber<? super T> s, Stream<T> stream
6969
}
7070

7171
if (s instanceof ConditionalSubscriber) {
72-
s.onSubscribe(new StreamConditionalSubscription<T>((ConditionalSubscriber<? super T>)s, iterator, stream));
72+
s.onSubscribe(new StreamConditionalSubscription<>((ConditionalSubscriber<? super T>)s, iterator, stream));
7373
} else {
7474
s.onSubscribe(new StreamSubscription<>(s, iterator, stream));
7575
}
@@ -147,15 +147,23 @@ public T poll() {
147147
once = true;
148148
} else {
149149
if (!iterator.hasNext()) {
150+
clear();
150151
return null;
151152
}
152153
}
153-
return Objects.requireNonNull(iterator.next(), "Iterator.next() returned a null value");
154+
return Objects.requireNonNull(iterator.next(), "The Stream's Iterator.next() returned a null value");
154155
}
155156

156157
@Override
157158
public boolean isEmpty() {
158-
return iterator == null || !iterator.hasNext();
159+
Iterator<T> it = iterator;
160+
if (it != null) {
161+
if (!once || it.hasNext()) {
162+
return false;
163+
}
164+
clear();
165+
}
166+
return true;
159167
}
160168

161169
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/**
2+
* Copyright (c) 2016-present, RxJava Contributors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
5+
* compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is
10+
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
11+
* the License for the specific language governing permissions and limitations under the License.
12+
*/
13+
package io.reactivex.rxjava3.internal.jdk8;
14+
15+
import java.util.Objects;
16+
import java.util.function.*;
17+
import java.util.stream.Collector;
18+
19+
import io.reactivex.rxjava3.annotations.NonNull;
20+
import io.reactivex.rxjava3.core.*;
21+
import io.reactivex.rxjava3.disposables.Disposable;
22+
import io.reactivex.rxjava3.exceptions.Exceptions;
23+
import io.reactivex.rxjava3.internal.disposables.*;
24+
import io.reactivex.rxjava3.internal.observers.DeferredScalarDisposable;
25+
import io.reactivex.rxjava3.plugins.RxJavaPlugins;
26+
27+
/**
28+
* Collect items into a container defined by a Stream {@link Collector} callback set.
29+
*
30+
* @param <T> the upstream value type
31+
* @param <A> the intermediate accumulator type
32+
* @param <R> the result type
33+
* @since 3.0.0
34+
*/
35+
public final class ObservableCollectWithCollector<T, A, R> extends Observable<R> {
36+
37+
final Observable<T> source;
38+
39+
final Collector<T, A, R> collector;
40+
41+
public ObservableCollectWithCollector(Observable<T> source, Collector<T, A, R> collector) {
42+
this.source = source;
43+
this.collector = collector;
44+
}
45+
46+
@Override
47+
protected void subscribeActual(@NonNull Observer<? super R> observer) {
48+
A container;
49+
BiConsumer<A, T> accumulator;
50+
Function<A, R> finisher;
51+
52+
try {
53+
container = collector.supplier().get();
54+
accumulator = collector.accumulator();
55+
finisher = collector.finisher();
56+
} catch (Throwable ex) {
57+
Exceptions.throwIfFatal(ex);
58+
EmptyDisposable.error(ex, observer);
59+
return;
60+
}
61+
62+
source.subscribe(new CollectorObserver<>(observer, container, accumulator, finisher));
63+
}
64+
65+
static final class CollectorObserver<T, A, R>
66+
extends DeferredScalarDisposable<R>
67+
implements Observer<T> {
68+
69+
private static final long serialVersionUID = -229544830565448758L;
70+
71+
final BiConsumer<A, T> accumulator;
72+
73+
final Function<A, R> finisher;
74+
75+
Disposable upstream;
76+
77+
boolean done;
78+
79+
A container;
80+
81+
CollectorObserver(Observer<? super R> downstream, A container, BiConsumer<A, T> accumulator, Function<A, R> finisher) {
82+
super(downstream);
83+
this.container = container;
84+
this.accumulator = accumulator;
85+
this.finisher = finisher;
86+
}
87+
88+
@Override
89+
public void onSubscribe(@NonNull Disposable d) {
90+
if (DisposableHelper.validate(this.upstream, d)) {
91+
this.upstream = d;
92+
93+
downstream.onSubscribe(this);
94+
}
95+
}
96+
97+
@Override
98+
public void onNext(T t) {
99+
if (done) {
100+
return;
101+
}
102+
try {
103+
accumulator.accept(container, t);
104+
} catch (Throwable ex) {
105+
Exceptions.throwIfFatal(ex);
106+
upstream.dispose();
107+
onError(ex);
108+
}
109+
}
110+
111+
@Override
112+
public void onError(Throwable t) {
113+
if (done) {
114+
RxJavaPlugins.onError(t);
115+
} else {
116+
done = true;
117+
upstream = DisposableHelper.DISPOSED;
118+
this.container = null;
119+
downstream.onError(t);
120+
}
121+
}
122+
123+
@Override
124+
public void onComplete() {
125+
if (done) {
126+
return;
127+
}
128+
129+
done = true;
130+
upstream = DisposableHelper.DISPOSED;
131+
A container = this.container;
132+
this.container = null;
133+
R result;
134+
try {
135+
result = Objects.requireNonNull(finisher.apply(container), "The finisher returned a null value");
136+
} catch (Throwable ex) {
137+
Exceptions.throwIfFatal(ex);
138+
downstream.onError(ex);
139+
return;
140+
}
141+
142+
complete(result);
143+
}
144+
145+
@Override
146+
public void dispose() {
147+
super.dispose();
148+
upstream.dispose();
149+
}
150+
}
151+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/**
2+
* Copyright (c) 2016-present, RxJava Contributors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
5+
* compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is
10+
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
11+
* the License for the specific language governing permissions and limitations under the License.
12+
*/
13+
package io.reactivex.rxjava3.internal.jdk8;
14+
15+
import java.util.Objects;
16+
import java.util.function.*;
17+
import java.util.stream.Collector;
18+
19+
import io.reactivex.rxjava3.annotations.NonNull;
20+
import io.reactivex.rxjava3.core.*;
21+
import io.reactivex.rxjava3.disposables.Disposable;
22+
import io.reactivex.rxjava3.exceptions.Exceptions;
23+
import io.reactivex.rxjava3.internal.disposables.*;
24+
import io.reactivex.rxjava3.internal.fuseable.FuseToObservable;
25+
import io.reactivex.rxjava3.plugins.RxJavaPlugins;
26+
27+
/**
28+
* Collect items into a container defined by a Stream {@link Collector} callback set.
29+
*
30+
* @param <T> the upstream value type
31+
* @param <A> the intermediate accumulator type
32+
* @param <R> the result type
33+
* @since 3.0.0
34+
*/
35+
public final class ObservableCollectWithCollectorSingle<T, A, R> extends Single<R> implements FuseToObservable<R> {
36+
37+
final Observable<T> source;
38+
39+
final Collector<T, A, R> collector;
40+
41+
public ObservableCollectWithCollectorSingle(Observable<T> source, Collector<T, A, R> collector) {
42+
this.source = source;
43+
this.collector = collector;
44+
}
45+
46+
@Override
47+
public Observable<R> fuseToObservable() {
48+
return new ObservableCollectWithCollector<>(source, collector);
49+
}
50+
51+
@Override
52+
protected void subscribeActual(@NonNull SingleObserver<? super R> observer) {
53+
A container;
54+
BiConsumer<A, T> accumulator;
55+
Function<A, R> finisher;
56+
57+
try {
58+
container = collector.supplier().get();
59+
accumulator = collector.accumulator();
60+
finisher = collector.finisher();
61+
} catch (Throwable ex) {
62+
Exceptions.throwIfFatal(ex);
63+
EmptyDisposable.error(ex, observer);
64+
return;
65+
}
66+
67+
source.subscribe(new CollectorSingleObserver<>(observer, container, accumulator, finisher));
68+
}
69+
70+
static final class CollectorSingleObserver<T, A, R> implements Observer<T>, Disposable {
71+
72+
final SingleObserver<? super R> downstream;
73+
74+
final BiConsumer<A, T> accumulator;
75+
76+
final Function<A, R> finisher;
77+
78+
Disposable upstream;
79+
80+
boolean done;
81+
82+
A container;
83+
84+
CollectorSingleObserver(SingleObserver<? super R> downstream, A container, BiConsumer<A, T> accumulator, Function<A, R> finisher) {
85+
this.downstream = downstream;
86+
this.container = container;
87+
this.accumulator = accumulator;
88+
this.finisher = finisher;
89+
}
90+
91+
@Override
92+
public void onSubscribe(@NonNull Disposable d) {
93+
if (DisposableHelper.validate(this.upstream, d)) {
94+
this.upstream = d;
95+
96+
downstream.onSubscribe(this);
97+
}
98+
}
99+
100+
@Override
101+
public void onNext(T t) {
102+
if (done) {
103+
return;
104+
}
105+
try {
106+
accumulator.accept(container, t);
107+
} catch (Throwable ex) {
108+
Exceptions.throwIfFatal(ex);
109+
upstream.dispose();
110+
onError(ex);
111+
}
112+
}
113+
114+
@Override
115+
public void onError(Throwable t) {
116+
if (done) {
117+
RxJavaPlugins.onError(t);
118+
} else {
119+
done = true;
120+
upstream = DisposableHelper.DISPOSED;
121+
this.container = null;
122+
downstream.onError(t);
123+
}
124+
}
125+
126+
@Override
127+
public void onComplete() {
128+
if (done) {
129+
return;
130+
}
131+
132+
done = true;
133+
upstream = DisposableHelper.DISPOSED;
134+
A container = this.container;
135+
this.container = null;
136+
R result;
137+
try {
138+
result = Objects.requireNonNull(finisher.apply(container), "The finisher returned a null value");
139+
} catch (Throwable ex) {
140+
Exceptions.throwIfFatal(ex);
141+
downstream.onError(ex);
142+
return;
143+
}
144+
145+
downstream.onSuccess(result);
146+
}
147+
148+
@Override
149+
public void dispose() {
150+
upstream.dispose();
151+
upstream = DisposableHelper.DISPOSED;
152+
}
153+
154+
@Override
155+
public boolean isDisposed() {
156+
return upstream == DisposableHelper.DISPOSED;
157+
}
158+
}
159+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* Copyright (c) 2016-present, RxJava Contributors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
5+
* compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is
10+
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
11+
* the License for the specific language governing permissions and limitations under the License.
12+
*/
13+
package io.reactivex.rxjava3.internal.jdk8;
14+
15+
import java.util.NoSuchElementException;
16+
17+
/**
18+
* Signals the first element of the source via the underlying CompletableFuture,
19+
* signals the a default item if the upstream is empty or signals {@link NoSuchElementException}.
20+
*
21+
* @param <T> the element type
22+
* @since 3.0.0
23+
*/
24+
public final class ObservableFirstStageObserver<T> extends ObservableStageObserver<T> {
25+
26+
final boolean hasDefault;
27+
28+
final T defaultItem;
29+
30+
public ObservableFirstStageObserver(boolean hasDefault, T defaultItem) {
31+
this.hasDefault = hasDefault;
32+
this.defaultItem = defaultItem;
33+
}
34+
35+
@Override
36+
public void onNext(T t) {
37+
complete(t);
38+
}
39+
40+
@Override
41+
public void onComplete() {
42+
if (!isDone()) {
43+
clear();
44+
if (hasDefault) {
45+
complete(defaultItem);
46+
} else {
47+
completeExceptionally(new NoSuchElementException());
48+
}
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)