我怎么能让Unchecked Exception冒泡并登录?

时间:2017-06-23 13:57:18

标签: java exception exception-handling

引自this页面,标题为:异常处理反模式博客,似乎是由Oracle编写(或至少得到批准)..

  

可能不应该重试未经检查的异常,并且正确的响应通常是什么都不做,并让它从您的方法和执行堆栈中冒出来。这就是为什么它不需要在throws子句中声明。最终,在高执行级别,可能会记录异常。

我不确定我是否理解这一点。如何记录未经检查的异常?如果我有类似的东西:

public static void main(String args) {
    foo();
    // How do I know what to log here? The method I am calling
    // is not throwing an Exception. 
    // Do I just blindly catch(Exception ex)?
}

static void foo() {
    bar();
}

static void bar() {
    baz();
}

static void baz() {
    // I will do nothing as Oracle suggests and let this exception bubble up.. I wonder who is going to catch it and how this is going to be logged though!
    throw new NullPointerException();
}

您能帮我理解Oracle在这里提出的建议吗?我没有看到任何直接(或明确)的方法来捕获运行时异常我不明白为什么它不仅仅被称为未经检查的异常... )更高级别我我不确定这个建议的做法是如何有用的。对我而言,如果谈论已检查的例外会更有意义。像...这样的东西。

  

如果在一个不合理的方法中抛出一个检查过的异常,那么正确的反应是让它冒泡并记录..

8 个答案:

答案 0 :(得分:2)

您还可以注册一个全局ExceptionHandler,它将处理代码未捕获的异常:

var i = new Intent();
i.SetType("*/*");
Forms.Context.StartActivity(Intent.CreateChooser(i, ""));

此异常句柄可以记录发生的任何事情。

答案 1 :(得分:1)

首先,这是一般性建议,取决于具体情况。它背后的想法是,当发生运行时异常时(例如NullPointerException),系统通常处于不确定状态,这意味着其余代码不能保证按预期执行,因此最好停止一切。

在大多数情况下,您的代码将在一个单独的线程中运行,异常只会停止当前线程,而程序的其余部分将继续运行。

在您的示例中不是这种情况,因为所有内容都在一个线程中执行,因此未捕获的异常将有效地停止整个程序。在这种情况下,您可能希望捕获异常并处理它。

public static void main(String args) {
    try {
        foo();
    catch(Throwable t) {
        t.printStackTrace(); // log exception
        // handle the failure
    }
}

您也可以在之前捕获异常,进一步记录并重新抛出异常。

static void bar() {
    try {
        baz();
    catch (Throwable t) {    // catch
        t.printStackTrace(); // log
        throw t;             // rethrow further
    }
}

编辑:抓住Throwable代替Exception,也会抓住Error

注意:捕获throwable通常是一个坏主意,并且只应该用于特定目的,而不是一般情况下。见@ RC。的评论。

答案 2 :(得分:0)

据我了解,该文档建议您在代码的高级别拥有一个通用处理程序,以记录这些“意外”的错误信息。 (不可恢复的?)异常就像你的主要方法中的评论所暗示的那样。所以它可能看起来像这样

public static void main(String args) {
    try {
      foo();
    } 
    catch (ArithmeticException aex) { //if it's arithmetic log differently
         log("arith issue! "+aex.getMessage());
    } 
    catch (Exception ex) { //Otherwise do the best we can 
            log("unknown issue! "+ex.getMessage())
    } 
}

因此,仍然没有恢复的途径,但至少在流程结束之前,您有机会记录问题。在许多情况下,您还可以使用Exception(或throwable)方法来获取堆栈跟踪和第一个因果异常 - 因此可能会记录许多额外的有用信息。

答案 3 :(得分:0)

我如何知道在此登录的内容?我调用的方法不是抛出异常。

Joshua Bloch 建议在 Effective Java

  

使用Javadoc @throws标记记录每个未经检查的异常   方法可以抛出,但不要使用throws关键字来包含   方法声明中未经检查的异常

如果您在多层应用程序中使用方法换行,我可以建议使用异常翻译

  

更高层应该捕获较低级别的异常,并且取而代之的是抛出可以用更高级别抽象来解释的异常

请参阅Effective Java item 61

所以我认为你的例子实际上应该使用类似的东西:

try {
 bar();
} catch(NullPointerException e) {
 throw new HigherLevelException(...);
}

答案 4 :(得分:0)

有一种非常简单的方法可以捕获未经检查的异常,因为它们都是RuntimeExceptionError的子类:

public static void main(String[] args) {
    try {
        // your code
    } catch (RuntimeException | Error e) {
        // handle uncaught exceptions, e.g.
        e.printStackTrace();
    }
}

答案 5 :(得分:0)

关于例外的最重要的指导原则是,一个无法成功完成其任务的方法应该抛出异常。

只有当您可以保证成功完成方法的任务时,您才应该在方法中捕获异常(不会重新抛出此异常或其他异常)。根据我的经验,这种情况仅在非常具体的情况下才有效,例如:如果你有另一种尝试,如果第一次尝试失败,或者你真的了解你将要捕获的这个特定Exception类的所有可能原因。

谈到RuntimeExceptions时,有很多不同类型的RuntimeException,你几乎无法证明像#34这样的断言;当我的代码中出现这样的异常或者从我的代码中调用的方法时,它就赢了影响我的方法的结果 - 我可以继续,好像什么也没发生。"所以,你应该向你的调用者发出你未能完成任务的信号,最明确的方法就是让异常通过,而不用try / catch块或throws声明,只依赖于Java的默认行为

在我看来,同样的推理适用于几乎所有类型的异常,而不仅仅是RuntimeExceptions。

与已检查异常的区别在于您必须在方法的throws子句中声明它们。然后你有两个选择:列出方法的throws子句中的异常(以及所有父方法!)或捕获异常,将其包装在新的RuntimeException(ex)中,并从方法中抛出它。

例如一个典型的GUI应用程序,如果一个菜单功能中的问题不会导致整个应用程序崩溃,您的用户将不胜感激 - 可能其他菜单项可能仍然按预期工作。因此,顶级命令或菜单项通常是捕获异常的地方,告诉用户类似于"糟糕!",将异常记录到某个文件以供以后检查,并允许用户继续另一个行动。

在你的主/ foo / bar / baz应用程序中,我没有看到在异常有意义之后继续的地方。所以应该中止整个程序(在你的情况下会自动发生)。如果您希望将某些错误记录到文件中,那么建立一个未捕获的异常处理程序或在try / catch(Throwable t)块中包装main()的主体。您可能希望记录每个异常,无论它是什么类型,所以抓住它们,这就是我建议Throwable的原因。

答案 6 :(得分:-1)

您可以像使用try-catch块的任何其他异常一样捕获它们。但好处是你没必要。

用例可能有所不同。在我看来,最流行的是当在那个地方捕获异常没有意义,或者应该在比方法更高的几个级别(在方法方面)实现适当的处理,调用抛出异常的那个(对不起,如果不够清楚的话。)

例如,java中典型的Web应用程序布局如下:您有一层控制器,一层服务和一层dao。第一个负责调度请求,第二个负责管理业务逻辑,最后一个负责实际调用db。因此,例如,如果在dao级别出现问题,捕获服务层中的异常通常没有多大意义。这里可以使用未经检查的异常。您记录一个异常并抛出一个未经检查的异常,以便可以在上面处理某些级别,以便用户获得有关应用程序工作的宝贵反馈。

如果在这种情况下你抛出一个已检查的异常,你将不得不重新抛出它上面的每个级别,只是将它冒泡到实际处理的位置。所以这里使用未经检查的异常更好,以便不复制和粘贴所有丑陋的try-catch块,重新抛出异常并将throws子句添加到方法中。

答案 7 :(得分:-1)

public static void main(String[] args) {
        try {
            foo();
        }
        catch(NullPointerException e){
               System.out.println("NullPointerException in main.");
        }        
    }

    static void foo() {
        bar();
    }

    static void bar() {
        baz();
    }

    static void baz() {
        // I will do nothing as Oracle suggests and let this exception bubble up.. I wonder who is going to catch it and how this is going to be logged though!
        throw new NullPointerException();
    }

输出

NullPointerException in main.

基本上错误预期在更高的级别,因此不需要在baz()方法级别上捕获它。如果我理解正确的话。

相关问题