你会如何拦截所有例外情况?

时间:2009-10-02 12:57:10

标签: java exception interceptor

根据您的说法,拦截Java应用程序中所有异常的最简单方法是什么? 是否需要AOP来提供这种功能,还是可以使用动态代理来实现,还是有其他方式? 最简单的解决方案是否也是影响执行性能的良好解决方案? 我希望听到更有经验的开发人员可能的解决方案,因为我正在努力掌握有关该主题的技术知识。

修改

感谢您提供了很好的建议,但目前的建议是否仅适用于已检查的例外情况?那些未经检查的异常,如NullPointerExceptions,如果可以捕获它们并且捕获它们的应用程序转储堆/堆栈以便在崩溃时为您提供应用程序的当前上下文,那么它会不会有用呢?

7 个答案:

答案 0 :(得分:11)

您希望拦截每个例外的目的是什么 - 用于记录,错误报告?

可以拦截Java程序的每一行中的每个异常,但可能会产生相当大的性能损失。如果它是不可避免的,那么最好使用类似AspectJ的东西,它可以在编译时运行(即它“编织”到你的类文件中),因此比动态代理要快得多。

但我会尽量避免不惜一切代价!一般来说,我会说最好限制你想要捕获的异常的范围。您也可以查看Thread.setDefaultUncaughtExceptionHandler,我认为这对于在GUI应用程序中显示错误对话框非常有用。

答案 1 :(得分:9)

与Phil的回答类似,这里有一些示例代码,展示了如何使用未捕获的异常处理程序。这适用于已检查和未检查的异常。

编辑:更新以根据问题中的更新评论打印堆栈跟踪。

import java.lang.Thread.UncaughtExceptionHandler;

public class Test {

    public static void main(String[] args) throws Exception {
        Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {

            @Override
            public void uncaughtException(Thread t, Throwable e) {
                e.printStackTrace();
            }}

        );

        // throw new RuntimeException(); /* this works too */
        throw new Exception();
    }

}

答案 2 :(得分:5)

在Nate和Konamiman ......你所建议的内容根本不起作用,也没有回答OP的问题。

如果OP从你的try / catch中启动一个新线程怎么办?

例如:

public static void main(String[] args) {
    try {
        final Thread t = new Thread( new Runnable() {
            public void run() {
                System.out.println( 3 / Math.min(0,4) );
            }
        } );
        t.start();
    catch(Throwable t) {
        ...
    }
}

然后你没有抓住异常。

正确的方法是使用Thread.setDefaultUncaughtExceptionHandler。

答案 3 :(得分:3)

public static void main(String[] args) {
    try {
        ...
    catch(Throwable t) {
        ...
    }
}

答案 4 :(得分:0)

更重要的是,除了捕获所有异常之外,还有什么可以捕获异常:

  1. 除非您可以对此做些什么,否则不要捕获异常。如果你无法做任何事情,要么让它冒泡到一个新的水平或抓住它,重新包装它作为一个更具体的例外并重新抛出它。

  2. 总是有一个全局异常处理块(比如在Nate的回答中)来捕捉你在任何地方都无法处理的任何错误,这样你就可以稍微优雅地失败。

答案 5 :(得分:0)

如果您只想捕获异常,则try / catch块就足够了。如果你想阻止它们被抛出或者做一些日志记录或包装,你可能需要一些AOP才能做到这一点。 AspectJ将很好地处理它,但要注意潜在的性能瓶颈。

动态代理仅在代理方法时才有效,因此如果抛出任何异常并在代理对象的执行中捕获,则代理无法拦截异常。

要考虑的一件事是,您是要捕获所有异常,还是仅检查异常。为了捕获所有异常,AspectJ的around throwingafter throwing建议将围绕每个方法编织一些处理,这涉及在每个方法调用时创建JoinPoint对象和合成方法。这通常不是问题,除非进程处于紧密循环中,垃圾收集可以通过屋顶。

答案 6 :(得分:0)

对于所有那些质疑需要捕获所有例外的人......

有一个很多有效理由来捕获所有例外:

  • 有人提到在GUI应用程序中显示一个告诉问题的对话框
  • 解决您真正需要的第三方API中的错误
  • 解决某些JVM实现中的错误
  • 自我修复软件。
  • 自动在线异常报告。

请注意,Java 本身会拦截EDT(事件调度线程)上的所有异常,并在EDT死亡时生成新的EDT。您可以考虑使用一种“自我修复”软件。 EDT死亡并不是闻所未闻的,并不能完全阻止应用程序正常运行(相反)。 (并且,是的,Swing和AWT有一些错误,只需看看Sun bug游行;)

可以说任何自尊软件都应该考虑到一个无法预料的异常情况(你所发布的所有软件都是100%无错误且永远不会获得新版本,错误修复版本?)并做一些事情这种不可预见的异常发生时很聪明。

'聪明的东西'可能会阻止软件崩溃(比如在EDT案例中),警告用户,发送报告等等。

回答质疑是否需要做这样的事情,或者建议这样做是不好的做法,应该恕我直言。