RxJava 的威力在於操作符鏈:將數據流經過聲明式變換、過濾、合併、聚合,最終交給 Subscriber。本文以搜索建議、標題抓取為業務場景,層層遞進講解 map、flatMap、filter、take、doOnNext 等核心操作符的組合藝術。
Observable.just("Hello, world!")
.map(s -> s + " -Dan")
.subscribe(System.out::println);
// 輸出: Hello, world! -Dan
T → 輸出類型 R,可改變類型(String → Integer)。map 依次執行,等價於單個組合函數。Observable flatMap(Function super T, ? extends ObservableSource extends R>> mapper)
將上游每個發射項 T 轉換為一個 Observable,**扁平化合併**所有內部 Observable 的發射序列,順序**不保證**(并發合併)。
// 假設接口
Observable> query(String text); // 返回 URL 列表
Observable getTitle(String url); // 返回標題(可能 404 發射 null)
// 錯誤寫法:訂閱嵌套 → Callback Hell
query("RxJava").subscribe(urls ->
Observable.from(urls).subscribe(url ->
getTitle(url).subscribe(title -> ...) // 三層嵌套!
)
);
// 正確寫法:flatMap 鏈式扁平化
query("RxJava")
.flatMap(urls -> Observable.fromIterable(urls)) // List → Observable
.flatMap(url -> getTitle(url)) // String → Observable
.filter(title -> title != null) // 過濾 404
.take(5) // 只取前 5 個
.doOnNext(title -> saveTitle(title)) // 副作用:持久化
.subscribe(title -> System.out.println(title));
| 特性 | 說明 |
|---|---|
| 并發合併 | 內部 Observable 默認并發訂閱,發射順序不可預測 |
| 保序替代 | 需保序用 concatMap(串行等待上一個完成)或 switchMap(取消舊訂閱) |
| 錯誤傳播 | 任一內部 Observable 錯誤 → 整條流錯誤,可用 onErrorResumeNext 降級 |
| 背壓 | RxJava 2+ Flowable.flatMap 支持背壓參數控制并發度 |
query("keywords")
.flatMap(urls -> Observable.fromIterable(urls)) // 1. 展開列表
.flatMap(url -> getTitle(url)) // 2. 異步獲取標題
.filter(title -> title != null) // 3. 過濾無效
.take(5) // 4. 限制數量
.doOnNext(title -> saveTitle(title)) // 5. 副作用(不影響流)
.subscribe(title -> renderUI(title)); // 6. 終端消費
每個操作符單一職責,組合出極其靈活的數據流管道。修改需求(如改成取前 10 個、加緩存、換線程)只需增刪一行,業務邏輯清晰可見。
| 類別 | 代表 | 核心語義 |
|---|---|---|
| 創建 | just, fromIterable, create, defer, interval, range | 構建源頭 Observable |
| 變換 | map, flatMap, concatMap, switchMap, scan, groupBy | 項目轉換/流重組 |
| 過濾 | filter, take, skip, first, last, distinct, ignoreElements | 控制通過項 |
| 合併 | merge, concat, zip, combineLatest, amb, join | 多流組合策略 |
| 聚合 | reduce, collect, count, toList, toMap, toSortedList | 歸約為單值/集合 |
| 副作用 | doOnNext, doOnError, doOnComplete, doOnSubscribe, doOnDispose | 旁路邏輯(日志/埋點/緩存) |
| 調度 | subscribeOn, observeOn | 指定上游/下游線程池 |
| 錯誤處理 | onErrorReturn, onErrorResumeNext, retry, retryWhen | 降級/重試策略 |
| 條件/布爾 | all, any, contains, isEmpty, defaultIfEmpty | 流級判斷 |
flatMap + subscribeOn(Schedulers.io()) 異步化。flatMap/concatMap。compositeDisposable.clear(),防內存洩漏。Flowable + BackpressureStrategy。subscribeOn 只影響上游,**最近的生效**;observeOn 可多次切換下游線程。RxJava 操作符是「函數式編程的積木」:map 做同步變換,flatMap 做異步扁平化,filter/take 做流控,doOnNext 做副作用。掌握組合而非繼承的思維,將業務拆解為操作符管道,代碼將極具可讀性、可測試性與可維護性。