Skip to content

Commit 5200cfc

Browse files
committed
Fixed the issue about null values
1 parent 02e14dc commit 5200cfc

File tree

1 file changed

+74
-32
lines changed

1 file changed

+74
-32
lines changed

rxjava-core/src/main/java/rx/operators/OperationTakeLast.java

+74-32
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,22 @@
1515
*/
1616
package rx.operators;
1717

18-
import static org.mockito.Matchers.*;
19-
import static org.mockito.Mockito.*;
18+
import static org.mockito.Matchers.any;
19+
import static org.mockito.Mockito.inOrder;
20+
import static org.mockito.Mockito.mock;
21+
import static org.mockito.Mockito.never;
22+
import static org.mockito.Mockito.times;
23+
import static org.mockito.Mockito.verify;
2024

21-
import java.util.Iterator;
22-
import java.util.concurrent.LinkedBlockingDeque;
25+
import java.util.Deque;
26+
import java.util.LinkedList;
27+
import java.util.concurrent.locks.ReentrantLock;
2328

2429
import org.junit.Test;
2530
import org.mockito.InOrder;
2631

2732
import rx.Observable;
2833
import rx.Observable.OnSubscribeFunc;
29-
import rx.subscriptions.Subscriptions;
3034
import rx.Observer;
3135
import rx.Subscription;
3236

@@ -60,45 +64,36 @@ private static class TakeLast<T> implements OnSubscribeFunc<T> {
6064
}
6165

6266
public Subscription onSubscribe(Observer<? super T> observer) {
63-
if(count == 0) {
64-
items.subscribe(new Observer<T>() {
65-
66-
@Override
67-
public void onCompleted() {
68-
}
69-
70-
@Override
71-
public void onError(Throwable e) {
72-
}
73-
74-
@Override
75-
public void onNext(T args) {
76-
}
77-
78-
}).unsubscribe();
79-
observer.onCompleted();
80-
return Subscriptions.empty();
67+
if (count < 0) {
68+
throw new IndexOutOfBoundsException(
69+
"count could not be negative");
8170
}
82-
8371
return subscription.wrap(items.subscribe(new ItemObserver(observer)));
8472
}
8573

8674
private class ItemObserver implements Observer<T> {
8775

88-
private LinkedBlockingDeque<T> deque = new LinkedBlockingDeque<T>(count);
76+
/**
77+
* Store the last count elements until now.
78+
*/
79+
private Deque<T> deque = new LinkedList<T>();
8980
private final Observer<? super T> observer;
81+
private final ReentrantLock lock = new ReentrantLock();
9082

9183
public ItemObserver(Observer<? super T> observer) {
9284
this.observer = observer;
9385
}
9486

9587
@Override
9688
public void onCompleted() {
97-
Iterator<T> reverse = deque.descendingIterator();
98-
while (reverse.hasNext()) {
99-
observer.onNext(reverse.next());
89+
try {
90+
for (T value : deque) {
91+
observer.onNext(value);
92+
}
93+
observer.onCompleted();
94+
} catch (Throwable e) {
95+
observer.onError(e);
10096
}
101-
observer.onCompleted();
10297
}
10398

10499
@Override
@@ -107,9 +102,27 @@ public void onError(Throwable e) {
107102
}
108103

109104
@Override
110-
public void onNext(T args) {
111-
while (!deque.offerFirst(args)) {
112-
deque.removeLast();
105+
public void onNext(T value) {
106+
if (count == 0) {
107+
// If count == 0, we do not need to put value into deque and
108+
// remove it at once. We can ignore the value directly.
109+
return;
110+
}
111+
lock.lock();
112+
try {
113+
deque.offerLast(value);
114+
if (deque.size() > count) {
115+
// Now deque has count + 1 elements, so the first
116+
// element in the deque definitely does not belong
117+
// to the last count elements of the source
118+
// sequence. We can drop it now.
119+
deque.removeFirst();
120+
}
121+
} catch (Throwable e) {
122+
observer.onError(e);
123+
subscription.unsubscribe();
124+
} finally {
125+
lock.unlock();
113126
}
114127
}
115128

@@ -174,6 +187,35 @@ public void testTakeLastWithZeroCount() {
174187
verify(aObserver, times(1)).onCompleted();
175188
}
176189

190+
@Test
191+
public void testTakeLastWithNull() {
192+
Observable<String> w = Observable.from("one", null, "three");
193+
Observable<String> take = Observable.create(takeLast(w, 2));
194+
195+
@SuppressWarnings("unchecked")
196+
Observer<String> aObserver = mock(Observer.class);
197+
take.subscribe(aObserver);
198+
verify(aObserver, never()).onNext("one");
199+
verify(aObserver, times(1)).onNext(null);
200+
verify(aObserver, times(1)).onNext("three");
201+
verify(aObserver, never()).onError(any(Throwable.class));
202+
verify(aObserver, times(1)).onCompleted();
203+
}
204+
205+
@Test
206+
public void testTakeLastWithNegativeCount() {
207+
Observable<String> w = Observable.from("one");
208+
Observable<String> take = Observable.create(takeLast(w, -1));
209+
210+
@SuppressWarnings("unchecked")
211+
Observer<String> aObserver = mock(Observer.class);
212+
take.subscribe(aObserver);
213+
verify(aObserver, never()).onNext("one");
214+
verify(aObserver, times(1)).onError(
215+
any(IndexOutOfBoundsException.class));
216+
verify(aObserver, never()).onCompleted();
217+
}
218+
177219
}
178220

179221
}

0 commit comments

Comments
 (0)