
doFinally 并非自动附加到任意 Observable 实例,而是返回一个新 Observable;若未将其结果用于后续订阅,该操作将被丢弃——这是导致 doFinally 看似“不触发”的根本原因。
`dofinally` 并非自动附加到任意 observable 实例,而是返回一个**新 observable**;若未将其结果用于后续订阅,该操作将被丢弃——这是导致 `dofinally` 看似“不触发”的根本原因。
在 RxJava(尤其是 RxJava 3+)中,所有操作符(包括 doFinally)均为无副作用的纯函数式转换:它们不修改原 Observable,而是创建并返回一个具备新增行为的新 Observable。因此,若仅调用 observable.doFinally(...) 而未将返回值用于订阅或链式传递,该 doFinally 将完全被忽略——这正是示例代码中输出缺失 "Test do finally before" 和 "Test do finally after" 的根本原因。
错误写法解析:三路分离,仅一路执行
原始代码构建了三个独立的 Observable 链:
observable.doFinally(() -> System.out.println("before")); // ❌ 未订阅,被丢弃
observable.blockingSubscribe(...); // ✅ 执行,但未含 doFinally
observable.doFinally(() -> System.out.println("after")); // ❌ 同样未订阅,被丢弃
这等价于创建了三条互不关联的流水线,只有 blockingSubscribe() 对应的那条实际运行,其余两条因无订阅而永不触发。
正确写法:链式调用,确保 doFinally 被纳入执行流
必须将 doFinally 的返回值作为下一步操作的输入,形成连续的数据流:
public static void main(String[] args) {
System.out.println("Start");
Observable<integer> source = Observable.create(emitter -> {
emitter.onNext(1);
emitter.onComplete();
});
// ✅ 正确:doFinally 返回新 Observable,并立即用于 blockingSubscribe
source
.doFinally(() -> System.out.println("Test do finally before"))
.blockingSubscribe(
System.out::println, // onNext
System.err::println, // onError
() -> System.out.println("ON Complete") // onComplete
);
System.out.println("End");
}</integer>
输出结果:
Start Test do finally before 1 ON Complete End
⚠️ 注意执行时机:doFinally 在 整个 Observable 生命周期结束时触发(即 onComplete/onError 发出后,或下游主动取消订阅时),但它不阻塞 blockingSubscribe() 的返回——因此 "Test do finally before" 实际发生在 onComplete 之后、blockingSubscribe() 方法返回之前,而非严格“在 onComplete 之后打印”,这点需结合线程模型理解。
进阶建议:避免 blockingSubscribe 与 doFinally 的时序混淆
若需确保 doFinally 的副作用绝对发生在所有事件处理完毕且主线程继续执行前,推荐使用非阻塞 subscribe() + 显式同步控制(如 CountDownLatch),或直接将清理逻辑放在 onComplete 回调中:
source.subscribe(
System.out::println,
Throwable::printStackTrace,
() -> {
System.out.println("ON Complete");
System.out.println("Test do finally before"); // ✅ 语义明确,时机可控
}
);
总结
- doFinally 是转换操作符,必须参与链式调用并最终被订阅;
- 每次调用操作符都生成新 Observable,原对象不受影响;
- 在 blockingSubscribe 场景下,doFinally 会在阻塞等待结束后、方法返回前执行;
- 若需精确控制副作用顺序,优先考虑在 onComplete 回调中执行,或使用 doOnTerminate + 条件判断(适用于需区分完成/错误场景)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











