快速瞭解非同步程式設計 RxJava
前言
前段時間寫了一篇對協程的一些理解,裡面提到了不管是協程還是callback,本質上其實提供的是一種非同步無阻塞的程式設計模式;並且介紹了java中對非同步無阻賽這種程式設計模式的支援,主要提到了Future和CompletableFuture;之後有同學在下面留言提到了RxJava,剛好最近在看微服務設計這本書,裡面提到了響應式擴充套件(Reactive extensions,Rx),而RxJava是Rx在JVM上的實現,所有打算對RxJava進一步瞭解。
RxJava簡介
RxJava的官網地址:https://github.com/ReactiveX/RxJava,
其中對RxJava進行了一句話描述:RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.
大意就是:一個在Java VM上使用可觀測的序列來組成非同步的、基於事件的程式的庫。
更詳細的說明在Netflix技術部落格的一篇文章中描述了RxJava的主要特點:
- 易於併發從而更好的利用伺服器的能力。
- 易於有條件的非同步執行。
- 一種更好的方式來避免回撥地獄。
- 一種響應式方法。
與CompletableFuture對比
之前提到CompletableFuture真正的實現了非同步的程式設計模式,一個比較常見的使用場景:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(耗時函式); Future<Integer> f = future.whenComplete((v, e) -> { System.out.println(v); System.out.println(e); }); System.out.println("other...");
下面用一個簡單的例子來看一下RxJava是如何實現非同步的程式設計模式:
bservable<Long> observable = Observable.just(1, 2) .subscribeOn(Schedulers.io()).map(new Func1<Integer, Long>() { @Override public Long call(Integer t) { try { Thread.sleep(1000); //耗時的操作 } catch (InterruptedException e) { e.printStackTrace(); } return (long) (t * 2); } }); observable.subscribe(new Subscriber<Long>() { @Override public void onCompleted() { System.out.println("onCompleted"); } @Override public void onError(Throwable e) { System.out.println("error" + e); } @Override public void onNext(Long result) { System.out.println("result = " + result); } }); System.out.println("other...");
Func1中以非同步的方式執行了一個耗時的操作,Subscriber(觀察者)被訂閱到Observable(被觀察者)中,當耗時操作執行完會回撥Subscriber中的onNext方法。
其中的非同步方式是在subscribeOn(Schedulers.io())中指定的,Schedulers.io()可以理解為每次執行耗時操作都啟動一個新的執行緒。
結構上其實和CompletableFuture很像,都是非同步的執行一個耗時的操作,然後在有結果的時候主動告訴我結果。那我們還需要RxJava幹嘛,不知道你有沒有注意,上面的例子中其實提供2條資料流[1,2],並且處理完任何一個都會主動告訴我,當然這只是它其中的一項功能,RxJava還有很多好用的功能,在下面的內容會進行介紹。
非同步觀察者模式
上面這段程式碼有沒有發現特別像設計模式中的:觀察者模式;首先提供一個被觀察者Observable,然後把觀察者Subscriber新增到了被觀察者列表中;
RxJava中一共提供了四種角色:Observable、Observer、Subscriber、Subjects
Observables和Subjects是兩個被觀察者,Observers和Subscribers是觀察者;
當然我們也可以檢視一下原始碼,看一下jdk中的Observer和RxJava的Observer
jdk中的Observer:
public interface Observer { void update(Observable o, Object arg); }
RxJava的Observer:
public interface Observer<T> { void onCompleted(); void onError(Throwable e); void onNext(T t); }
同時可以發現Subscriber是implements Observer的:
public abstract class Subscriber<T> implements Observer<T>, Subscription
可以發現RxJava中在Observer中引入了2個新的方法:onCompleted()和onError()
onCompleted():即通知觀察者Observable沒有更多的資料,事件佇列完結
onError():在事件處理過程中出異常時,onError()會被觸發,同時佇列自動終止,不允許再有事件發出。
正是因為RxJava提供了同步和非同步兩種方式進行事件的處理,個人覺得非同步的方式更能體現RxJava的價值,所以這裡給他命名為非同步觀察者模式。
好了,下面正式介紹RxJava的那些靈活的操作符,這裡僅僅是簡單的介紹和簡單的例項,具體用在什麼場景下,會在以後的文章中介紹
Maven引入
<dependency> <groupId>io.reactivex</groupId> <artifactId>rxjava</artifactId> <version>1.2.4</version> </dependency>
建立Observable
1.create()建立一個Observable,併為它定義事件觸發規則
Observable<Integer> observable = Observable .create(new Observable.OnSubscribe<Integer>() { @Override public void call(Subscriber<? super Integer> observer) { for (int i = 0; i < 5; i++) { observer.onNext(i); } observer.onCompleted(); } }); observable.subscribe(new Observer<Integer>() {...});
2.from()可以從一個列表中建立一個Observable,Observable將發射出列表中的每一個元素
List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items.add(i); } Observable<Integer> observable = Observable.from(items); observable.subscribe(new Observer<Integer>() {...});
3.just()將傳入的引數依次傳送出來
Observable<Integer> observable = Observable.just(1, 2, 3); observable.subscribe(new Observer<Integer>() {...});
過濾Observable
1.filter()來過濾我們觀測序列中不想要的值
List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items.add(i); } Observable<Integer> observable = Observable.from(items).filter( new Func1<Integer, Boolean>() { @Override public Boolean call(Integer t) { return t == 1; } }); observable.subscribe(new Observer<Integer>() {...});
2.take()和taskLast()分別取前幾個元素和後幾個元素
List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items.add(i); } Observable<Integer> observable = Observable.from(items).take(3); observable.subscribe(new Observer<Integer>() {...});
Observable<Integer> observable = Observable.from(items).takeLast(2);
3.distinct()和distinctUntilChanged()
distinct()過濾掉重複的值
List<Integer> items = new ArrayList<Integer>(); items.add(1); items.add(10); items.add(10); Observable<Integer> observable = Observable.from(items).distinct(); observable.subscribe(new Observer<Integer>() {...});
distinctUntilChanged()列發射一個不同於之前的一個新值時讓我們得到通知
List<Integer> items = new ArrayList<Integer>(); items.add(1); items.add(100); items.add(100); items.add(200); Observable<Integer> observable = Observable.from(items).distinctUntilChanged(); observable.subscribe(new Observer<Integer>() {...});
4.first()和last()分別取第一個元素和最後一個元素
List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items.add(i); } // Observable<Integer> observable = Observable.from(items).first(); Observable<Integer> observable = Observable.from(items).last(); observable.subscribe(new Observer<Integer>() {...});
5.skip()和skipLast()分別從前或者後跳過幾個元素
List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items.add(i); } // Observable<Integer> observable = Observable.from(items).skip(2); Observable<Integer> observable = Observable.from(items).skipLast(2); observable.subscribe(new Observer<Integer>() {...});
6.elementAt()取第幾個元素進行發射
List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items.add(i); } Observable<Integer> observable = Observable.from(items).elementAt(2); observable.subscribe(new Observer<Integer>() {...});
7.sample()指定發射間隔進行發射
List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 50000; i++) { items.add(i); } Observable<Integer> observable = Observable.from(items).sample(1,TimeUnit.MICROSECONDS); observable.subscribe(new Observer<Integer>() {...});
8.timeout()設定的時間間隔內如果沒有得到一個值則發射一個錯誤
List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items.add(i); } Observable<Integer> observable = Observable.from(items).timeout(1,TimeUnit.MICROSECONDS); observable.subscribe(new Observer<Integer>() {...onError()...});
9.debounce()在一個指定的時間間隔過去了仍舊沒有發射一個,那麼它將發射最後的那個
List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items.add(i); } Observable<Integer> observable = Observable.from(items).debounce(1,TimeUnit.MICROSECONDS); observable.subscribe(new Observer<Integer>() {...});
轉換Observable
1.map()接收一個指定的Func物件然後將它應用到每一個由Observable發射的值上
List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items.add(i); } Observable<Integer> observable = Observable.from(items).map( new Func1<Integer, Integer>() { @Override public Integer call(Integer t) { return t * 2; } }); observable.subscribe(new Observer<Integer>() {...});
2.flatMap()函式提供一種鋪平序列的方式,然後合併這些Observables發射的資料
final Scheduler scheduler = Schedulers.from(Executors.newFixedThreadPool(3)); List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items.add(i); } Observable<Integer> observable = Observable.from(items).flatMap( new Func1<Integer, Observable<? extends Integer>>() { @Override public Observable<? extends Integer> call(Integer t) { List<Integer> items = new ArrayList<Integer>(); items.add(t); items.add(99999); return Observable.from(items).subscribeOn(scheduler); } }); observable.subscribe(new Observer<Integer>() {...});
重要的一點提示是關於合併部分:它允許交叉。這意味著flatMap()不能夠保證在最終生成的Observable中源Observables確切的發射
順序。
3.concatMap()函式解決了flatMap()的交叉問題,提供了一種能夠把發射的值連續在一起的鋪平函式,而不是合併它們。
示例程式碼同上,將flatMap替換為concatMap,輸出的結果來看是有序的
4.switchMap()和flatMap()很像,除了一點:每當源Observable發射一個新的資料項(Observable)時,它將取消訂閱並停止監視之前那個資料項產生的Observable,並開始監視當前發射的這一個。
示例程式碼同上,將flatMap替換為switchMap,輸出的結果只剩最後一個值
5.scan()是一個累積函式,對原始Observable發射的每一項資料都應用一個函式,計算出函式的結果值,並將該值填充回可觀測序列,等待和下一次發射的資料一起使用。
List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items.add(i); } Observable<Integer> observable = Observable.from(items).scan( new Func2<Integer, Integer, Integer>() { @Override public Integer call(Integer t1, Integer t2) { System.out.println(t1 + "+" + t2); return t1 + t2; } }); observable.subscribe(new Observer<Integer>() {...});
6.groupBy()來分組元素
List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items.add(i); } Observable<GroupedObservable<Integer, Integer>> observable = Observable .from(items).groupBy(new Func1<Integer, Integer>() { @Override public Integer call(Integer t) { return t % 3; } }); observable.subscribe(new Observer<GroupedObservable<Integer, Integer>>() { @Override public void onNext(final GroupedObservable<Integer, Integer> t) { t.subscribe(new Action1<Integer>() { @Override public void call(Integer value) { System.out.println("key:" + t.getKey()+ ", value:" + value); } }); });
7.buffer()函式將源Observable變換一個新的Observable,這個新的Observable每次發射一組列表值而不是一個一個發射。
List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items.add(i); } Observable<List<Integer>> observable = Observable.from(items).buffer(2); observable.subscribe(new Observer<List<Integer>>() {...});
8.window()函式和 buffer()很像,但是它發射的是Observable而不是列表
List<Integer> items = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items.add(i); } Observable<Observable<Integer>> observable = Observable.from(items).window(2); observable.subscribe(new Observer<Observable<Integer>>() { @Override public void onNext(Observable<Integer> t) { t.subscribe(new Action1<Integer>() { @Override public void call(Integer t) { System.out.println("this Action1 = " + this+ ",result = " + t); } }); //onCompleted和onError });
9.cast()它將源Observable中的每一項資料都轉換為新的型別,把它變成了不同的Class
List<Father> items = new ArrayList<Father>(); items.add(new Son()); items.add(new Son()); items.add(new Father()); items.add(new Father()); Observable<Son> observable = Observable.from(items).cast(Son.class); observable.subscribe(new Observer<Son>() {...}); class Father { } class Son extends Father { }
組合Observables
1.merge()方法將幫助你把兩個甚至更多的Observables合併到他們發射的資料項裡
List<Integer> items1 = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items1.add(i); } List<Integer> items2 = new ArrayList<Integer>(); for (int i = 5; i < 10; i++) { items2.add(i); } Observable<Integer> observable1 = Observable.from(items1); Observable<Integer> observable2 = Observable.from(items2); Observable<Integer> observableMerge = Observable.merge(observable1,observable2); observable.subscribe(new Observer<Integer>() {...});
2.zip()合併兩個或者多個Observables發射出的資料項,根據指定的函式 Func* 變換它們,併發射一個新值
List<Integer> items1 = new ArrayList<Integer>(); for (int i = 0; i < 5; i++) { items1.add(i); } List<Integer> items2 = new ArrayList<Integer>(); for (int i = 5; i < 10; i++) { items2.add(i); } Observable<Integer> observable1 = Observable.from(items1); Observable<Integer> observable2 = Observable.from(items2); Observable<Integer> observableZip = Observable.zip(observable1, observable2, new Func2<Integer, Integer, Integer>() { @Override public Integer call(Integer t1, Integer t2) { return t1 * t2; } }); observable.subscribe(new Observer<Integer>() {...});
3.combineLatest()把兩個Observable產生的結果進行合併,這兩個Observable中任意一個Observable產生的結果,都和另一個Observable最後產生的結果,按照一定的規則進行合併。
Observable<Long> observable1 = Observable.interval(1000,TimeUnit.MILLISECONDS); Observable<Long> observable2 = Observable.interval(1000,TimeUnit.MILLISECONDS); Observable.combineLatest(observable1, observable2, new Func2<Long, Long, Long>() { @Override public Long call(Long t1, Long t2) { System.out.println("t1 = " + t1 + ",t2 = " + t2); return t1 + t2; } }).subscribe(new Observer<Long>() {...}); Thread.sleep(100000);
4.join()類似combineLatest(),但是join操作符可以控制每個Observable產生結果的生命週期,在每個結果的生命週期內,可以與另一個Observable產生的結果按照一定的規則進行合併
Observable<Long> observable1 = Observable.interval(1000, TimeUnit.MILLISECONDS); Observable<Long> observable2 = Observable.interval(1000, TimeUnit.MILLISECONDS); observable1.join(observable2, new Func1<Long, Observable<Long>>() { @Override public Observable<Long> call(Long t) { System.out.println("left=" + t); return Observable.just(t).delay(1000, TimeUnit.MILLISECONDS); } }, new Func1<Long, Observable<Long>>() { @Override public Observable<Long> call(Long t) { System.out.println("right=" + t); return Observable.just(t).delay(1000, TimeUnit.MILLISECONDS); } }, new Func2<Long, Long, Long>() { @Override public Long call(Long t1, Long t2) { return t1 + t2; } }).subscribe(new Observer<Long>() { @Override public void onCompleted() { System.out.println("Observable completed"); } @Override public void onError(Throwable e) { System.out.println("Oh,no! Something wrong happened!"); } @Override public void onNext(Long t) { System.out.println("[result=]" + t); } }); Thread.sleep(100000);
5.switchOnNext()把一組Observable轉換成一個Observable,對於這組Observable中的每一個Observable所產生的結果,如果在同一個時間記憶體在兩個或多個Observable提交的結果,只取最後一個Observable提交的結果給訂閱者
Observable<Observable<Long>> observable = Observable.interval(2, TimeUnit.SECONDS) .map(new Func1<Long, Observable<Long>>() { @Override public Observable<Long> call(Long aLong) { return Observable.interval(1, TimeUnit.MILLISECONDS).take(5); } }).take(2); Observable.switchOnNext(observable).subscribe(new Observer<Long>() {...}); Thread.sleep(1000000);
6.startWith()在Observable開始發射他們的資料之前,startWith()通過傳遞一個引數來先發射一個資料序列
Observable.just(1000, 2000).startWith(1, 2).subscribe(new Observer<Integer>() {...});
總結
本文主要對rxjava進行了簡單的介紹,從非同步程式設計這個角度對rxjava進行了分析;並且針對Observable的過濾,轉換,組合的API進行了簡單的介紹,當然我們更關心的是rxjava有哪些應用場景。
相關文章
- 我瞭解到的JavaScript非同步程式設計JavaScript非同步程式設計
- 快速瞭解Web MVC設計模式WebMVC設計模式
- python 網路程式設計----非阻塞或非同步程式設計Python程式設計非同步
- [譯] 非同步程式設計:阻塞與非阻塞非同步程式設計
- Socket程式設計中的同步、非同步、阻塞和非阻塞(轉)程式設計非同步
- 一張圖快速瞭解23種設計模式設計模式
- 快速瞭解雲端計算
- 快速瞭解Python併發程式設計的工程實現(下)Python程式設計
- 快速瞭解Python併發程式設計的工程實現(上)Python程式設計
- 好程式設計師Java教程教你5分鐘瞭解快速排序程式設計師Java排序
- 向非程式設計師解釋JavaScript程式設計師JavaScript
- 向非程式設計師解釋 JavaScript程式設計師JavaScript
- Q:你瞭解非同步程式設計、程式、單執行緒、多執行緒嗎?非同步程式設計執行緒
- Flutter非同步程式設計詳解Flutter非同步程式設計
- 【進階之路】併發程式設計(三)-非阻塞同步機制程式設計
- Java網路程式設計和NIO詳解5:Java 非阻塞 IO 和非同步 IOJava程式設計非同步
- 響應式程式設計RxJava (一)程式設計RxJava
- 初步瞭解C語言Windows程式設計C語言Windows程式設計
- 一文徹底搞定(阻塞/非阻塞/同步/非同步)網路IO、併發程式設計模型、非同步程式設計模型的愛恨情仇非同步程式設計模型
- 程式設計師的“非程式設計師”之路程式設計師
- 快速瞭解jQueryjQuery
- 非同步程式設計非同步程式設計
- 響應式程式設計入門(RxJava)程式設計RxJava
- 響應式程式設計庫RxJava初探程式設計RxJava
- 用程式設計師的思維瞭解Filecoin程式設計師
- 只有程式設計師瞭解的9個真相程式設計師
- 程式設計是否真的要很瞭解基礎?程式設計
- Java 網路程式設計 —— 非阻塞式程式設計Java程式設計
- 基於 mysql 非同步驅動的非阻塞 Mybatis 瞭解一下MySql非同步MyBatis
- 解構反應式程式設計——Java8,RxJava,Reactor之比較程式設計RxJavaReact
- promise-java非同步程式設計解決方案PromiseJava非同步程式設計
- 非同步程式設計:基於事件的非同步程式設計模式(EAP)非同步程式設計事件設計模式
- Dart 非同步程式設計Dart非同步程式設計
- php非同步程式設計PHP非同步程式設計
- asyncio 非同步程式設計非同步程式設計
- js 非同步程式設計JS非同步程式設計
- 非同步程式設計---Promise非同步程式設計Promise
- Javascript 非同步程式設計JavaScript非同步程式設計