如何在没有丑陋的 instanceof 的情况下处理 Retrofit Rx onError 中的不同类型的错误

How to handle different kinds of errors in Retrofit Rx onError without ugly instanceof

我想知道您在改造 Rx onError 时如何处理不同类型的错误(如 http 异常、无互联网连接异常等),而不使用 instanceof,就像这里建议的那样: or here:

在 kotlin 中,我将简单地为每种 throwable 做一些扩展函数来做任何我想做的事情。

但是我在项目中被迫使用Java。有什么好的建议吗?

是构建某种错误处理程序的方法,如下所示:

public interface ErrorHandler {
    void handleError(Exception e);
    void handleError(HttpException e);
    void handleError(NullPointerException npe);

}

好吗?我知道这不是因为每次我需要处理另一个特定错误时我都被迫更改接口,所以这违反了开闭原则。但是我想不出任何解决办法。

干杯 沃伊泰克

编译器决定调用哪个方法,而不是 VM。因此,您所描述的 class 不会解决问题,除非您首先检查 instanceof 并将参数转换为正确的类型。否则你每次都会得到 handleError(Exception e) 。

但我想创建一个答案并不是出于这个原因,而是为了证明在许多情况下实际上只有一个错误处理程序更可取,而不是一种负担。在 java 中,我们经常会遇到这样糟糕的情况:

    catch (NoSuchAlgorithmException e) {
        throw new IllegalStateException("No such algorithm: RSA?", e);
    }
    catch (NoSuchProviderException e) {
        throw new IllegalStateException("No such provider: " + ANDROID_KEYSTORE_ID, e);
    }
    catch (InvalidAlgorithmParameterException e) {
        throw new IllegalStateException("Bug setting up encryption key for user credentials: ", e);
    }
    catch (KeyStoreException e) {
        throw new IllegalStateException("Bug setting up encryption key for user credentials: ", e);
    }
    catch (IOException e) {
        Log.w(TAG, "Exception setting up keystore for user creds. They won't be stored.", e);
    }
    catch (CertificateException e) {
        Log.w(TAG, "Exception setting up keystore for user creds. They won't be stored.", e);
    }

只有一个错误处理程序使我们能够将多种类型的异常集中在一起。您可以在这段代码中看到,存在永远不应抛出的异常、实际上只能由代码中的错误导致的异常以及我们需要处理的合法异常状态。我觉得这很乱,我更愿意说:

if (e instanceof NoSuchAlgorithmException || e instanceof NoSuchProviderException)  { 
    Log.wtf(TAG, "What the heck is this?", e);
    throw new IllegalStateException("This is some kind of weird bug", e);
}
else if (e instanceof IOException || e instanceof CertificateException) {
    // This can happen sometimes, track event in analytics and perhaps 
    // try some alternative means of credential storage.
} 
else {
    // At least here the app won't crash if some unexpected exception occurs,
    // since we're trapping everything.
} 

我认为能够将意外故障集中在一起并以比使应用程序崩溃更友好的方式处理它们并不是一件坏事。即使它只是一个错误,最好在幕后的分析框架中跟踪它,而不是将用户轰炸出应用程序。 Android 应用程序中的许多崩溃实际上是完全可以恢复的,但我们不会在每个 try/catch 语句中都捕获 Throwable,因为它有很多额外的代码。

避免链式 ifcatch 的正确 OOP 方法是 多态性 。您可以定义多个自定义异常 classes 公开足以让单个处理程序处理的公共接口。

假设您需要将错误分为两组:可恢复和不可恢复。然后你的基础异常class(或接口)应该有抽象方法isRecoverable(),你在每个子class中覆盖它。那么你的处理程序中将只有一个 ifif (e.isRecoverable()) { ... } else { ... }.

缺点是您必须在抛出它们的地方将所有标准异常包装到您的自定义异常中(您必须捕获它们)。

不过,正确的选择在很大程度上取决于您的任务。