在RxJava中我們可以很方便地處理異常,只要加上onError
即可。
不過,如果異常發生在操作符內部,比如flatMap
,那我們怎么把這個異常傳遞給onError
呢。
Checked異常和Unchecked異常
- Checked異常必須被顯式地捕獲或者傳遞,而unchecked異常則可以不必捕獲或拋出。
- Checked異常繼承java.lang.Exception類。Unchecked異常繼承自java.lang.RuntimeException類。
Unchecked異常
一般情況下,unchecked異常會自動傳遞給onError
。例如以下代碼可以打印出“Error!”。
Observable.just("Hello!")
.map(input -> {throw new RuntimeException();})
.subscribe(
System.out::println,
error -> System.out.println("Error!")
);
也有例外的情況,那就是... 那些非常嚴重的錯誤,以致于RxJava都不能繼續運行了。比如StackOverflowError
,這些異常被認為是致命的,對它們來說,調用<code>onError</code>毫無意義,并沒什么用。你可以用Exceptions.throwIfFatal
來過濾掉這些致命的異常并重新拋出,不發射關于它們的通知。
Checked異常
盡管RxJava有自己的異常處理機制,不過Checked異常還是必須由你的代碼來處理,也就是說,還是要自己加try-catch
。
假設我們用到這樣方法:
String transform(String input) throws IOException;
我們可以把Checked異常轉換為Unchecked異常,像這樣:
Observable.just("Hello!")
.map(input -> {
try {
return transform(input);
} catch (Throwable t) {
throw Exceptions.propagate(t);
}
});
Exceptions.propagate()
只是簡單地做了這樣一件事:如果異常是Checked異常,那就把它包裝成Unchecked異常。
而對于像flatMap
這樣返回Observable對象的操作,可以直接返回Observable.error()
。
Observable.just("Hello!")
.flatMap(input -> {
try {
return Observable.just(transform(input));
} catch (Throwable t) {
return Observable.error(t);
}
});
異常的屏蔽
很多RxJava初學者都犯了一個錯誤,過度地使用onError
,其實onError
應該在數據無法繼續處理下去時才使用。例如,在使用Retrofit 1的時候,響應的狀態碼為非200的結果調用onError
,這樣,我們在處理非200的響應結果時就會變得十分麻煩。這個問題在Retrofit 2已經解決了,現在可以通過Observable<Response<Type>>
和Observable<Result<Type>>
,來處理onNext
中的非200的結果返回。
也就是說,通常,你可以在發生錯誤的時候給onNext
一個錯誤的標識,然后直接在onNext
中處理問題,而不是跳過代碼進入onError
,這樣還是可以不中斷你的數據流,繼續運行你的代碼。
如何屏蔽異常而不把異常拋給onError
,以下有兩種選擇:
-
onErrorReturn()
,在遇到錯誤時發射一個特定的數據 -
onErrorResumeNext()
,在遇到錯誤時發射一個數據序列
Observable.just("Request data...")
.map(this::dangerousOperation)
.onErrorReturn(error -> "Empty result");
當dangerousOperation產生異常時,不會觸發onError
,而是返回字符串"Empty result"。
當上游的Observable
觀察到異常通知(onError
)時,通過onErrorReturn
或onErrorResumeNext
來把onError
轉換成與下游序列有所區分的數據。