如何在API的多种方法中集中处理异常

时间:2019-05-08 11:37:17

标签: java api exception error-handling

这是一个普通的Java 8+问题,未使用任何框架。

我们正在为更高层次的API进行处理,该API处理表示层以及其他活动。我们已经与调用者达成了接口协议,因此他们很高兴收到我们抛出的某些特殊异常。

同时,我们还在同一协议下使用其他API,因此我们可以自己做事并抛出异常,也可以调用引发约定的异常的其他API。 当前,我们对正在调用的API引发的异常不采取任何措施。

事实是,在引发异常的同时,我们在此基础结构中最适合处理中间活动,因此我们需要同时捕获我们的异常和所调用对象提供的异常。基本上报告问题,提高系统控制等,然后重新引发原始异常,以便顶层保持现在状态。

我们的API入口点类中大约有300种方法:

public void method1 (arguments for method 1) {
...
}

...

public void method300 (arguments for method 300) {
...
}

我清楚地知道,我可以创建一种方法来集中处理异常管理中要采取的措施,例如:

public void myExceptionHandler (Exception e) {
    if (e instanceOf X) {
    } else if ...
    ...
    throw particularExceptionAccordingTheCase 
}

但是我也避免修改这300种方法。

有什么主意如何在这300个方法中注入try-catch,以将异常发送到myExceptionHandler,而不必在每个方法中都添加try-catch?

任何评论和想法都非常感谢!

-----------在mprev0建议之后-------------------------------

我尝试了这种方法。它确实捕获了异常,依此类推,但是我无法重新抛出异常:我被迫捕获它,但这违反了将异常重新发送回顶层的要求。 虽然我可以抛出一个错误,但在抛出新FileNotFoundException()时却出现了编译器错误。

public class myExceptionHandler implements Thread.UncaughtExceptionHandler {

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("gotcha!");
        if (e instanceof java.lang.Error) {
            System.out.println("AAT-CORE: Fatal Error");
            throw new java.lang.Error(e.getCause());

        } else if (e instanceof java.lang.Exception) {
            System.out.println("AAT-CORE: Exception Error");
            throw new FileNotFoundException();
        }
    }

}

有什么想法吗?

------------经过更多挖掘后,用装饰器样式-------

先前的类实现无法正常工作,因为我无法更改方法的签名,因此需要重新抛出java.lang.Exception。

使用装饰器并在那里处理接口可以解决问题。 作为总结:

顶层类:

public class TopLayer {
    public static void main (String[] args) {
        MiddleLayer m = new MiddleLayer();
        m.method1();
    }
}

底层类包含​​特定的API和一些实现,唯一有趣的是它包含不受控制的java.lang.Exceptions,希望顶层可以完成此工作。但是,我们正在中间工作,我们将完成这项工作:

public class MiddleLayer extends BottomLayer {

    public MiddleLayer () {
        final UncaughtExceptionHandler subclass = Thread.currentThread().getUncaughtExceptionHandler();
        Thread.currentThread().setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread thread, Throwable ex) {

                System.out.println("gotcha2!");
                // carry on with prior flow
                subclass.uncaughtException(thread, ex);
            }
        });

    }

}

通过这种方式,我可以获取system.out并将java.lang.Exception传播到顶层。

装饰者的灵感来自这里:Rethrow UncaughtExceptionHandler Exception after Logging It

欢迎其他评论!

3 个答案:

答案 0 :(得分:4)

您可以通过实现java.lang.Thread.UncaughtExceptionHandler接口来解决此问题:

public class MyExceptionHandler implements Thread.UncaughtExceptionHandler {

    @Overrides
    public void uncaughtException(Thread t, Throwable e) {
            if (e instanceOf X) {
            } else if ...
            ...
            throw particularExceptionAccordingTheCase 
    }
}

然后将其与所有线程关联,如下所示:

Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler())

这将配置异常处理程序以处理应用程序所有线程中所有未捕获的异常。

请注意,这仅适用于尚未在代码中某个位置显式处理的异常,并且如果没有为某个特定线程配置其他处理程序(未捕获的异常处理程序也可以为某些特定线程设置)。 / p>

编辑:@JBC发现,上述方法不适用于已检查的异常,因为我们被迫在我们的 uncaughtException 方法中明确捕获它们(请注意, cannot add a throws clause to an overridden method)。虽然如果我们只想重新抛出RuntimeExceptionError的子类型,它将毫无问题地工作,但是如果我们想要使其工作,则需要一些修改-您可以在@JBC的问题。

答案 1 :(得分:0)

正如您在问题更新中所看到的那样,最终的解决方案是两种不同方法的组合,一方面,它具有实现java.lang.Thread.UncaughtExceptionHandler的mprev0方法,此外,还添加了一个装饰模式可以重新引发运行时异常。

到目前为止,还没有其他方法,因此我将结束这个问题并将其作为最完整的答复。

有关UncaughtExceptionHandler的更多信息可以在Java文档中找到,但是与往常一样,它缺少示例,在这里: Advanced exception handling Thread.UncaughtExceptionHandler Example

有关装饰器模式用法的更多信息,可以在这里找到: Decorator Design Pattern in Java Design Patterns - Decorator Pattern

以及如何在此处使用操作异常: Rethrow UncaughtExceptionHandler Exception after Logging It

答案 2 :(得分:-1)

您还可以在当前API的基础上创建代理API,在代理中具有调用处理程序方法,并将此方法放在try catch块中。

https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html

https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html