您将如何拦截所有异常?

发布于 2024-08-06 08:38:50 字数 313 浏览 6 评论 0原文

您认为拦截 Java 应用程序中所有异常的最简单方法是什么? 是否需要 AOP 来提供这种功能,或者可以使用动态代理来完成还是有其他方法? 考虑到对执行性能的影响,最简单的解决方案也是一个好的解决方案吗? 当我试图掌握有关该主题的技术知识时,我希望听到更有经验的开发人员提供的可能解决方案。

编辑:

感谢您提供的好建议,但是当前的建议不是仅适用于受检查的异常吗?对于像 NullPointerExceptions 这样的未经检查的异常,如果可以捕获这些异常并且捕获它们的应用程序转储堆/堆栈以向您提供崩溃时应用程序的当前上下文,这不是很有用吗?

What is according to you the simplest way to intercept all exceptions in a Java application?
Would AOP be needed to provide this kind of functionality or can it be done with dynamic proxies or is there another way?
Is the simplest solution also a good solution regarding impact on execution performance?
I would like to hear possible solutions from more experienced developers as I'm trying to grasp the technical know-how about the subject.

EDIT:

Thanks for the good advice already, but doesn't the current advice only apply to checked exceptions? What about unchecked exceptions, like NullPointerExceptions, wouldn't it be useful if these could be caught and that the application on catching them dumps the heap/stack to provide you with the current context of the application at the moment of crashing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

疯狂的代价 2024-08-13 08:38:50

您想要拦截每个异常的目的是什么 - 用于日志记录、错误报告?

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

但这是我会不惜一切代价尽量避免做的事情!一般来说,我会说最好限制您想要捕获的异常的范围。另外,您可能想查看 Thread.setDefaultUncaughtExceptionHandler,我发现它对于在 GUI 应用程序中显示错误对话框很有用。

What is the purpose of you wanting to intercept every exception - for logging, error reporting?

Intercepting every single exception in every single line of a Java program is possible, but would probably incur quite a performance hit. If it's unavoidable, it'd probably be best to use something like AspectJ, which can run at compile-time (i.e. it "weaves" into your class files) and as such is much faster than dynamic proxies.

But it's something I would try to avoid doing at all costs! In general I would say it's better to limit the scope of the exceptions you want to catch. Also you might want to look into Thread.setDefaultUncaughtExceptionHandler, which I find useful for displaying error dialogs in GUI applications.

蔚蓝源自深海 2024-08-13 08:38:50

与 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();
    }

}

Similar to Phil's answer, here is some sample code showing how to use the uncaught exception handler. This works for both checked and unchecked exceptions.

Edit: Updated to print the stack trace based on updated comments in the question.

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();
    }

}
没有你我更好 2024-08-13 08:38:50

在 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。

At Nate and Konamiman... What you're suggesting does not work at all and does not answer the OP's question.

What if the OP starts a new thread from inside your try/catch?

For example:

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) {
        ...
    }
}

Then you're not catching the exception.

The correct way to do it is to use Thread.setDefaultUncaughtExceptionHandler.

黯然#的苍凉 2024-08-13 08:38:50
public static void main(String[] args) {
    try {
        ...
    catch(Throwable t) {
        ...
    }
}
public static void main(String[] args) {
    try {
        ...
    catch(Throwable t) {
        ...
    }
}
何以畏孤独 2024-08-13 08:38:50

比简单地捕获所有异常更重要的是在哪里捕获异常:

  1. 不要捕获异常,除非您可以采取措施。如果你对此无能为力,要么让它冒泡到下一个级别,要么捕获它,将其重新包装为更具体的异常并重新抛出它。

  2. 始终有一个全局异常处理块(如 Nate 的答案)来捕获您无法在任何地方处理的任何错误,这样您就可以优雅地失败。

More importantly than simply catching all exceptions is WHERE you catch the exception:

  1. Don't catch an exception unless you can do something about it. If you can't do anything about it, either let it bubble up to the next level or catch it, re-wrap it as a more specific exception and re-throw it.

  2. Always have a global exception handling block (like in Nate's answer) to catch any errors you can't handle anywhere so you can fail somewhat gracefully.

巴黎盛开的樱花 2024-08-13 08:38:50

如果您只是想捕获异常,则 try/catch 块就足够了。如果您想防止抛出异常或对异常进行一些记录或包装,您可能需要一些 AOP 来执行此操作。 AspectJ 可以很好地处理它,但要注意潜在的性能瓶颈。

动态代理仅在方法被代理时才起作用,因此如果在代理对象的执行过程中抛出并捕获任何异常,则代理无法拦截该异常。

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

If you simply want to catch an Exception, a try/catch block will suffice. If you want to prevent them being thrown or do some logging or wrapping of the Exception, you will probably need some AOP to do this. AspectJ will handle it pretty well, but beware of potential performance bottlenecks.

Dynamic proxies will only work when the method is proxied, so if any Exception is thrown and caught inside the execution of the proxy object there is no means for the proxies to intercept the Exception.

One thing to consider is if you are catching all exceptions, or only checked exceptions. To catch all exceptions, AspectJ's around throwing or after throwing advice would weave some processing around every method, this involves the creation of JoinPoint objects and synthetic methods at every method invocation. This is not normally a problem unless the process is in a tight loop, where the garbage collection can go through the roof.

梨涡少年 2024-08-13 08:38:50

对于所有质疑是否需要捕获所有异常的人...

有很多有效的理由来捕获所有异常:

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

请注意,Java 本身确实会拦截 EDT(事件调度线程)上的所有异常,并在 EDT 终止时生成一个新的 EDT。您可以将其视为一种“自我修复”软件。 EDT 终止并不是闻所未闻的事情,并且不会完全阻止应用程序正常运行(相反)。 (是的,Swing 和 AWT 有相当多的错误,只需看看 Sun 的 bug 游行即可;)

可以说,任何有自尊心的软件实际上都应该考虑到不可预见的异常情况(所有软件都是如此)你发布了 100% 无错误的版本,并且从未获得新版本、错误修复版本?),并在发生此类不可预见的异常时采取明智的措施。

“智能的东西”可能会防止软件崩溃(就像在 EDT 的情况下)、警告用户、发送报告等。

回答质疑是否需要做这样的事情,或者建议这样做是一种不好的做法,恕我直言被改装。

To all those questionning the need to catch all exceptions...

There are a lot of valid reasons to catch all exceptions:

  • someone mentionned displaying a dialog in a GUI app telling about the problem
  • working around bugs in a 3rd party API you really need
  • working around bugs in some JVM implementation
  • self-healing software.
  • automatic online exception reporting.

Note that Java itself does intercept all exceptions on the EDT (Event Dispatch Thread) and spawns a new EDT when the EDT dies. You can consider that a form of "self-healing" software. The EDT dying is not something unheard of and doesn't exactly prevent the applications from running correctly (on the contrary). (and, yup, Swing and AWT have quite some bugs, just take a look at the Sun bug parade ;)

It could be argued that any self-respecting software should actually take into account the case of an unforeseen exception (are all the software you ship 100% bug free and never gets new releases, bug-fix releases?) and do something smart when such unforeseen exception happen.

The 'something smart' may be preventing the software from crashing (like in the EDT case), warning the user, sending a report, etc.

Answers questionning the need to do such a thing or suggesting that doing so is a bad practice should IMHO be modded down.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文