RxJava 操作符详解(2025-2026 实用版)
RxJava 的操作符(Operators)是其最核心、最强大的部分。理解操作符的分类和使用场景,比死记硬背单个操作符的名字更重要。
下面按实际使用频率和场景重要性排序,列出最常被问到、最常被用到的操作符,并标注典型使用场景、注意事项以及容易混淆的点。
一、最核心的分类与高频操作符一览表
| 分类 | 核心作用 | 高频操作符(按使用频率排序) | 面试/项目出现频率 |
|---|---|---|---|
| 创建型 | 如何产生 Observable | just / fromArray / fromIterable / range / interval / timer / create / defer / empty / never | ★★★★★ |
| 转换型 | 改变数据流中的元素 | map / flatMap / concatMap / switchMap / flatMapIterable / buffer / window / groupBy | ★★★★★ |
| 过滤型 | 筛选元素 | filter / take / takeLast / first / last / skip / elementAt / distinct / debounce / throttle | ★★★★☆ |
| 组合型 | 把多个 Observable 合并 | zip / combineLatest / merge / concat / amb / startWith / withLatestFrom | ★★★★☆ |
| 数学/聚合型 | 对序列做统计 | count / reduce / collect / average / max / min / sum | ★★★☆☆ |
| 辅助型 | 调试、延迟、错误处理 | doOnNext / doOnError / doOnComplete / doOnSubscribe / onErrorReturn / onErrorResumeNext | ★★★★☆ |
| 线程调度 | 控制上游/下游线程 | subscribeOn / observeOn | ★★★★★ |
| 背压控制 | 处理 Flowable 背压 | onBackpressureBuffer / onBackpressureDrop / onBackpressureLatest / onBackpressureError | ★★★★☆(Flowable) |
| 条件/布尔型 | 条件判断、序列控制 | all / any / contains / sequenceEqual / skipUntil / takeUntil / takeWhile / skipWhile | ★★★☆☆ |
| 连接型 | 控制何时开始发射 | publish / connect / refCount / replay / cache / share | ★★★☆☆ |
二、真正高频、面试必考的操作符详解(Top 12)
1. map / flatMap / concatMap / switchMap
| 操作符 | 一句话说明 | 常见使用场景 | 容易踩的坑 / 面试题 |
|---|---|---|---|
| map | 1:1 转换元素 | 类型转换、字段提取、计算 | — |
| flatMap | 1:N 转换 + 展平(无序) | 网络请求嵌套、列表扁平化 | 顺序不保证,适合“谁快用谁”场景 |
| concatMap | 1:N 转换 + 展平(严格保持顺序) | 需要严格顺序的嵌套请求 | 性能比 flatMap 差(必须等前一个完成) |
| switchMap | 最新数据源优先(旧的取消) | 搜索框输入防抖、切换 Tab 刷新数据 | 经典面试题:搜索框实现(防抖 + 最新请求优先) |
经典代码对比:
// 搜索框防抖 + 最新请求优先
searchEditText.textChanges()
.debounce(300, TimeUnit.MILLISECONDS)
.switchMap(query -> api.search(query))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(...);
2. zip / combineLatest / withLatestFrom
| 操作符 | 发射时机 | 典型场景 | 面试高频题 |
|---|---|---|---|
| zip | 所有源都发射一个才发射 | 多个接口同时请求,等齐了再显示(登录+用户信息) | “两个接口并发请求,等都成功才跳转页面” |
| combineLatest | 任意一个源发射就用最新的其他源组合 | 表单验证(用户名+密码都输入了才亮按钮) | “实时计算两个输入框的和” |
| withLatestFrom | 被观察者发射时,取观察者的最新值 | 点击按钮时取最新的配置/状态 | “点击发送时带上最新的 token” |
3. merge / concat / amb
| 操作符 | 合并方式 | 适用场景 |
|---|---|---|
| merge | 无序,谁发射快用谁 | 多个数据源,谁先到显示谁(新闻列表) |
| concat | 严格按顺序,先完成一个再下一个 | 广告 → 正文 → 评论(顺序必须保证) |
| amb | 哪个先发射就只用哪个 | 多个服务器取最快响应的那个(竞速) |
4. defer / interval / timer / range
| 操作符 | 特点 | 典型用法 |
|---|---|---|
| defer | 直到订阅才创建 Observable | 每次订阅都产生新数据(避免冷 Observable 共享状态) |
| interval | 每隔一段时间发射递增数字 | 轮询、倒计时、心跳 |
| timer | 延迟一段时间后发射 0L | 延迟执行、节流后操作 |
| range | 发射一段连续整数 | 生成测试数据、分页循环 |
5. 线程调度(必考)
Observable.just(1,2,3,4)
.subscribeOn(Schedulers.io()) // 上游(数据产生)线程
.observeOn(AndroidSchedulers.mainThread()) // 下游(消费)线程
.map(...)
.subscribe(...);
记住一句话:
subscribeOn 只生效一次(最上游的那个),observeOn 可以多次切换下游线程。
6. 错误处理操作符(生产必备)
| 操作符 | 作用 | 使用场景 |
|---|---|---|
| onErrorReturn | 错误时返回一个值,继续完成 | 网络错误时返回缓存数据 |
| onErrorResumeNext | 错误时切换到另一个 Observable | 主接口挂了,切备用接口 |
| onErrorReturnItem | 错误时返回单个值 | 简单降级 |
| retry / retryWhen | 重试机制 | 网络请求重试 |
| onExceptionResumeNext | 只捕获 Exception(不捕获 Error) | 更安全的错误恢复 |
三、2025-2026 年面试最常问的 RxJava 操作符组合题
- 搜索框防抖 + 最新请求优先 + 线程切换
- 并发请求两个接口,等齐了再显示(zip)
- 多个接口,谁先返回显示谁(merge / amb)
- 表单实时校验(combineLatest)
- 轮询接口,每 5 秒一次(interval + flatMap)
- 点击按钮时带上最新的 token(withLatestFrom)
- 嵌套请求需要严格顺序(concatMap)
- 错误时返回默认值或降级数据(onErrorReturn / onErrorResumeNext)
四、快速记忆口诀(背下来很有用)
- 想改变元素 → map / flatMap / concatMap / switchMap
- 想合并多个流 → zip(等齐)、combineLatest(最新组合)、merge(无序快)、concat(顺序)
- 想控制发射时机 → defer / publish / replay / cache
- 想处理错误 → onErrorReturn / onErrorResumeNext / retry
- 想控制线程 → subscribeOn(一次) / observeOn(多次)
你现在最想针对哪个操作符或场景来深入?
- 手写一个完整的搜索防抖 + 错误重试的链式调用?
- flatMap / concatMap / switchMap 三者的详细对比 + 动图解释?
- retryWhen 的高级用法(指数退避重试)?
- Flowable 背压场景下的操作符选择?
- 还是来几道经典 RxJava 面试手撕题?
告诉我你的需求,我继续陪你把 RxJava 操作符玩透~