在函数的情况下,当异常可能只在它们的执行位置抛出时(基于我缺乏知识,这对我来说目前还不确定),有时罪魁祸首可能依赖于 lambda 的创建方式,一个例子可能是:
// merge() will throw an exception if Function<S, Observable<T>> switchMap returns null.
public<S> void mergeSwitch(Observable<S> source, Function<S, Observable<T>> switchMap) {
final Mergeable<T> res = new Mergeable<>();
final Consumer<T> observer = creator(res, this); // Secondary subscription
setSource(
source, // Main subscription
new StateAwareObserver<S>() { // >>> implements Consumer<S>
Observable<T> switchRes = new Observable<>(); // Mediator
@Override
protected void onAdded() {
res.add(observer);
}
@Override
protected void onRemoved() {
res.remove(observer);
}
@Override
public void accept(S s) {
Observable<T> switchS = switchMap.apply(s);
if (switchRes != switchS) {
switchRes = switchS;
res.merge(switchS); //Where merge() throws if switchMap returns null
}
}
}
);
}
}
我尝试从 accept() 方法中重新抛出异常,但它永远不会被推(拉?)超出其消费点(消费者接受“s”的地方):
for (int i = observers.size() - 1; i >=0 ; i--) {
observers.get(i).accept(processed); // << -- StateAwareObserver<S> is stored in the *list*
}
- 在这种情况下,我使用“超越”这个词,但我需要的是在其构造点抛出异常。-
实际上,真正的罪魁祸首可能是方法的执行:mergeSwitch(Observable<S> source, Function<S, Observable<T>> switchMap)
它创建了 Consumer<>,可能遗漏了一些重要的东西。
或者就我而言,执行mergeSwitch()的方法:
public<S> Forkable<S> forkSwitch(Function<T, Observable<S>> switchMap) {
Forkable<S> res = new Forkable<>();
res.mergeSwitch(this, switchMap);
return res;
}
在这种情况下,问题是该函数留下了一个空值。
public Holders.Forkable<List<Preset>> ledgerPresets = presetDao.forkSwitch(
presetDao -> ledgerId.forkSwitch(
aLong -> null
)
);
因此,如果我们看一下消费者级别,真正的罪魁祸首是:
@Override
public void accept(S s) {
int sVersion = source.getVersion();
if (sVersion != oVersion) {
Observable3<T> switchS = switchMap.apply(s); //< -- HERE
if (switchRes != switchS) {
switchRes = switchS;
res.merge(switchS);
}
oVersion = sVersion;
}
}
在这种特殊情况下,事情很容易失控,因为日志可能不会在最近的消费点停止,但错误可能会一直回到根节点。
事情可能会变得更加复杂,因为作为异常起源的 merge() 方法可能已从 3 种不同的方法中使用。
理想的情况是在此处抛出异常:
public Holders.Forkable<List<Preset>> ledgerPresets = presetDao.forkSwitch(
presetDao -> ledgerId.forkSwitch( // <--- HERE
aLong -> null
)
);
但是我还没有找到一种方法来管理这个特殊的异常重新抛出案例。