RxJava 教程第二部分:事件流基礎之 檢查數據
Inspection 檢查數據是否符合某一條件
前面一節介紹了如何過濾掉我們不關心的數據。有時候我們需要了解該數據流中的數據是否符合某一條件。本節來介紹一些檢查數據流中數據的函數。
all
all 函數用來判斷 observable 中發射的所有數據是否都滿足一個條件。
public final Observable<java.lang.Boolean> all(Func1<? super T,java.lang.Boolean> predicate)
Observable<Integer> values = Observable.create(o -> {
o.onNext(0);
o.onNext(10);
o.onNext(10);
o.onNext(2);
o.onCompleted();
});
SubscriptionevenNumbers = values
.all(i -> i % 2 == 0)
.subscribe(
v -> System.out.println(v),
e -> System.out.println("Error: " + e),
() -> System.out.println("Completed")
);
結果:
true
Completed
all 函數返回的是一個發射一個 布爾值的 Observable,而不是直接返回一個 布爾值。原因在于我們并不知道源 Observable 何時才結束數據流的發射,只有當源 Observable 發射結束的時候, all 函數才知道結果是否都滿足條件。只要遇到一個不滿足條件的數據,all 函數就立刻返回 false。 只有當源 Observable 結束發射并且所發射的所有數據都滿足條件的時候才會產生 true。在 observable 內返回結果可以方便的實現非阻塞操作。 在下個示例中可以看到 all 在遇到不滿足的數據的時候就立刻結束了。
Observable<Long> values = Observable.interval(150, TimeUnit.MILLISECONDS).take(5);
Subscriptionsubscription = values
.all(i -> i<3) // Will fail eventually
.subscribe(
v -> System.out.println("All: " + v),
e -> System.out.println("All: Error: " + e),
() -> System.out.println("All: Completed")
);
Subscriptionsubscription2 = values
.subscribe(
v -> System.out.println(v),
e -> System.out.println("Error: " + e),
() -> System.out.println("Completed")
);
結果:
0
1
2
All: false
All: Completed
3
4
Completed
如果源 Observable 出現了錯誤,則 all 操作就沒有意義了,all 會直接發射一個 error 然后結束。
Observable<Integer> values = Observable.create(o -> {
o.onNext(0);
o.onNext(2);
o.onError(new Exception());
});
Subscriptionsubscription = values
.all(i -> i % 2 == 0)
.subscribe(
v -> System.out.println(v),
e -> System.out.println("Error: " + e),
() -> System.out.println("Completed")
);
結果:
Error: java.lang.Exception
如果源 Observable 在出錯之前就發射了一個不滿足條件的數據,則 源 Observable 的錯誤對 all 沒有影響( all 遇到不滿足條件的數據就結束了,結束的Observable 無法再繼續發射數據了)。
Observable<Integer> values = Observable.create(o -> {
o.onNext(1);
o.onNext(2);
o.onError(new Exception());
});
Subscriptionsubscription = values
.all(i -> i % 2 == 0)
.subscribe(
v -> System.out.println(v),
e -> System.out.println("Error: " + e),
() -> System.out.println("Completed")
);
結果:
false
Completed
exists
如果源 exists 發射的數據中有一個滿足條件,則 exists 就返回 true。 exists 和 all 一樣也是返回一個 Observable 而不是直接返回 布爾值。
Observable<Integer> values = Observable.range(0, 2);
Subscriptionsubscription = values
.exists(i -> i > 2)
.subscribe(
v -> System.out.println(v),
e -> System.out.println("Error: " + e),
() -> System.out.println("Completed")
);
結果:
false
Completed
上面示例中只發射了 0 和1 兩個數據,而這兩個數據都不滿足大于2的條件,所以返回結果為 false。如果我們多發射幾個數據,則就會滿足條件了。
Observable<Integer> values = Observable.range(0, 4);
結果:
true
Completed
isEmpty
顧名思義,判斷一個 Observable 是否是空的,也就是沒有發射任何數據就結束了。
Observable<Long> values = Observable.timer(1000, TimeUnit.MILLISECONDS);
Subscriptionsubscription = values
.isEmpty()
.subscribe(
v -> System.out.println(v),
e -> System.out.println("Error: " + e),
() -> System.out.println("Completed")
);
結果:
false
Completed
只要源 Observable 發射了一個數據,isEmpty 就立刻返回 false, 只有當源 Observable 完成了并且沒有發射數據,isEmpty 才返回 true。
contains
contains 使用 Object.equals 函數來判斷源 Observable 是否發射了相同的數據。只要遇到相同的數據,則 contains 就立刻返回。
Observable<Long> values = Observable.interval(100, TimeUnit.MILLISECONDS);
Subscriptionsubscription = values
.contains(4L)
.subscribe(
v -> System.out.println(v),
e -> System.out.println("Error: " + e),
() -> System.out.println("Completed")
);
結果:
true
Completed
注意上面使用的是 contains(4L), 而不是 contains(4), 由于 values 是 Observable
類型的, 所以需要使用 Long 類型而不能是 Integer 類型。
如果使用 contains(4) 則什么都不會打印出來, 由于 values 是一個無限的數據流,所以 contains 一直在等待一個相同的數據發射出來,但是在 values 里面是沒有一樣的數據的,導致 contains 一直等待下去。
defaultIfEmpty
如果你不想單獨處理沒有發射任何數據的情況(需要用 isEmpty 函數來檢查是否為空),則可以使用 defaultIfEmpty 函數來強制一個空的 Observable 發射一個默認數據。
Observable<Integer> values = Observable.empty();
Subscriptionsubscription = values
.defaultIfEmpty(2)
.subscribe(
v -> System.out.println(v),
e -> System.out.println("Error: " + e),
() -> System.out.println("Completed")
);
結果:
2
Completed
只有當 onCompleted 事件發生了,并且 Observable 沒有發射任何數據的時候,才會使用默認值;否則不會使用默認值。 如果發生了錯誤,則還會有錯誤的結果。
Observable<Integer> values = Observable.error(new Exception());
Subscriptionsubscription = values
.defaultIfEmpty(2)
.subscribe(
v -> System.out.println(v),
e -> System.out.println("Error: " + e),
() -> System.out.println("Completed")
);
結果:
Error: java.lang.Exception
elementAt
從特定的位置選擇一個數據發射。
Observable<Integer> values = Observable.range(100, 10);
Subscriptionsubscription = values
.elementAt(2)
.subscribe(
v -> System.out.println(v),
e -> System.out.println("Error: " + e),
() -> System.out.println("Completed")
);
結果:
102
Completed
該函數和訪問數組或者集合類似,如果 Observable 發射的數據個數沒有這么多,則會拋出 java.lang.IndexOutOfBoundsException 。可以使用一個默認值(elementAtOrDefault)來避免拋出 java.lang.IndexOutOfBoundsException。
Observable<Integer> values = Observable.range(100, 10);
Subscriptionsubscription = values
.elementAtOrDefault(22, 0)
.subscribe(
v -> System.out.println(v),
e -> System.out.println("Error: " + e),
() -> System.out.println("Completed")
);
結果:
0
Completed
sequenceEqual
本節最后這個操作函數是用來比較兩個 Observable 發射的數據是否是一樣的,同樣位置的數據是一樣的。要求兩個 Observable 發射的數據個數是一樣的并且每個位置上的數據也是一樣的。 該函數內部用 Object.equals 來比較數據,當然你也可以自己指定一個比較函數。
Observable<String> strings = Observable.just("1", "2", "3");
Observable<Integer> ints = Observable.just(1, 2, 3);
Observable.sequenceEqual(strings, ints, (s,i) -> s.equals(i.toString()))
//Observable.sequenceEqual(strings, ints)
.subscribe(
v -> System.out.println(v),
e -> System.out.println("Error: " + e),
() -> System.out.println("Completed")
);
結果:
true
Completed
上面使用了自定義的比較函數,所以結果是一樣的。 如果不指定自定義的 比較函數的話, 使用默認的 Object.equals 來比較,則返回的結果就是 False 了。
如果一個源 Observable 出現了 錯誤,則 比較結果的 Observable 也會出現 錯誤并結束。
Observable<Integer> values = Observable.create(o -> {
o.onNext(1);
o.onNext(2);
o.onError(new Exception());
});
Observable.sequenceEqual(values, values)
.subscribe(
v -> System.out.println(v),
e -> System.out.println("Error: " + e),
() -> System.out.println("Completed")
);
結果:
Error: java.lang.Exception