【问题标题】:What's Your ShouldNeverHappenException? [closed]你的 ShouldNeverHappenException 是什么? [关闭]
【发布时间】:2009-07-14 12:44:14
【问题描述】:

Java 的已检查异常有时会迫使您捕获您认为永远不会抛出的已检查异常。最佳实践要求您将其包装在未经检查的异常中并重新抛出它,以防万一。在这种情况下,你包装了什么异常类?

在“// 永远不会发生”的情况下,你会用什么例外来包装?

【问题讨论】:

  • 你是什么意思 - 用于表示“不应该发生”的场景,或者应该引发异常的特定场景?
  • throw new IllegalStateException("宇宙的基础数学已经被破解");
  • NullPointerExceptions 永远不会发生。

标签: java exception


【解决方案1】:

我还没有,但我会这样做:

  • 让它扩展 Error 而不是 Exception/RuntimeException,因为那样它就不太可能被未准备好的错误处理程序捕获;
  • 将其包装在一些静态实用程序调用中:

例子:

public static void doAssert(boolean result, String reason) {

    if ( !result ) 
        throw new OMGWereDoomedError("Assertion failed: " + reason + " .");
}

我更喜欢这些包装器,因为我可以根据需要更改实现。

另外,我不提倡使用断言,因为我并不总是控制运行时标志,但我确实希望在系统受到威胁时突然停止执行。

考虑一下:

  • 向用户显示抱歉,我们无法处理您的付款页面;
  • 向用户确认结果,即使系统处于不确定状态。

你会选择哪个?

【讨论】:

  • +1 表示错误类名:D
  • 保留错误。一个合理的应用程序不应该试图捕捉:java.sun.com/j2se/1.4.2/docs/api/java/lang/Error.html
  • @dfa:我同意,而且我正在走一条很细的线。但是,我宁愿在 uncatchExceptionHandler 中而不是在一些通用的 catch ( Exception e ) 块中获取这些。
【解决方案2】:

例如,我需要注意的是 to-UTF-8-bytes 字符转换

String.getBytes("UTF-8");

并且需要始终将其包装在 try-catch 中,因为它是一种通用方法。由于 UTF-8 可以被视为标准,我希望在字符串上直接调用 String.getUTF8(),类似于 GetStringUTF8Bytes JNI 方法。

当然,它可以替换为静态 Charset.UTF8 常量,例如使用 getBytes()。

对我来说,第二个烦恼是需要将close() 包装成try-catch。也许我没有那么有经验,但是当您已经遇到流问题并且您甚至无法默默地永久关闭它时,看不到它有什么帮助。您实际上只需记录并忽略异常。

显然,您可以使用抑制器方法调用来做到这一点。

当您通过正则表达式或模式验证检查字符串时,100% 确定字符串是有效值时,也会进行一些简单的值字符串转换。

【讨论】:

  • Close 在某些情况下可能会抛出 IOException,但实际上它必须写入内容(IIRC BufferedOutputStream 会将剩余的字符写入 close() 如果它们没有以其他方式刷新())。因此 close() 有时意味着 flush_then_close()
  • 是的。谢谢。我从来没有想过,因为我在关闭之前手动执行 flush()。
【解决方案3】:

我使用 AssertionError 和字符串 这永远不会发生

【讨论】:

  • 我将 RuntimeException 与“这不应该发生”一起使用。
  • 我使用 AssertionError 因为它没有被 catch(Exception) 捕获。是的,有些人就是这样写代码的。
  • 自我介绍。我之前一直犯抓异常,主要是在使用反射时。一般来说,它类似于从属性加载一个类并 newInstance 它。如果它失败了,继续你的生活[记录它]。对于视图插件之类的东西(在 OSGi 之前)我做了很多。
【解决方案4】:

任何属于 RuntimeException 或其后代的类都不需要放在方法的 throws 子句中。因此,如果您不希望有人因为它不应该发生而不得不处理它,那么请使用它。

对于诸如“无法连接到数据库”之类的事情是有意义的,因为如果您的数据库不可用,您的应用程序将无法运行。因此,您抛出一个运行时异常,启动应用程序的人将其视为一个问题。但是您不需要在调用堆栈中一直在 throws 中声明它。

【讨论】:

    【解决方案5】:

    不可能发生的异常

    【讨论】:

      【解决方案6】:

      我喜欢“到达无法访问的代码”

      【讨论】:

        【解决方案7】:

        这更适用于original version of the question,在编辑问题以专门处理捕获检查异常之前。

        免责声明:我最初在对该问题的评论中发布了此内容的 sn-p,因为该问题当时已关闭。

        int salary = ...;
        
        if (salary == 0) {
            // ...
        } else if (salary < 0) {
            // ...
        } else if (salary > 0) {
            // ...
        } else {
            throw new IllegalStateException("The fundamental mathematics of the universe have been compromised");
        }
        

        【讨论】:

          【解决方案8】:

          永远不应该发生的是错误而不是异常。异常描述了您可能可以处理的情况。你想如何处理突发事件?因为它是一个断言,这个特殊的异常永远不会发生,我会使用AssertionError

          【讨论】:

            【解决方案9】:

            除非代码不正确,否则永远不会发生的情况应使用断言进行检查。这样您就可以在生产版本中禁用它们。

            但我不喜欢留下一个简单的assert false;,我也不想写像 default case in switch should never firex 应该是非空这样愚蠢的消息em>,*这不应该发生”。它不应该,但它确实发生了。无论如何。此外,当你看到一条抱怨某事不应该的消息时,这听起来是不是有点抱怨> ? 另外,我不希望在可执行文件中包含大量这些消息,因为它们通常从未使用过,而且它们中的每一个都只与数千个函数中的某个小函数相关。

            所以我很喜欢

             assert false : "Programming Error"
            

            编程错误正是阻止应用程序工作的原因,因此它非常适合这种情况。

             switch (x)
             {
                 case GO_FORWARD:
                      ... break
                 case BUY_SWORD;
                      ... break
                 default:
                      assert false : "Programming Error"
             }
            
            
             /* at this point, we have already had checked that
                we have the money */
             try {
                  buy_sword(); buy_elixir();
             } catch (InsufficientFunds) {
                  /* if the code was correct, the funds would be sufficient
                     so this event means the code is broken. Telling
                     the user something like "Funds should be sufficient"
                     won't be helpful to the user, so we put in a generic error message */
                  throw new AssertionError("Programming Error");
             }
            

            如果您想始终运行这些检查,那么不要

             assert false : "Programming Error"
             assert expr : "Programming Error"
            

             if (! expr)
                  throw new Exception("Programming Error")
            

            甚至派生ProgrammingError异常类。

            【讨论】:

            • 断言在正常情况下不会运行。这意味着在测试期间(使用 -ea),如果您没有点击您的断言语句之一,您可以在未定义的状态下静默继续(除非您的生产代码也使用 -ea)。
            • 我同意这是个问题。在没有断言的情况下运行的测试可能会遗漏问题。当仅使用断言运行测试时,您可能会面临断言被破坏并产生副作用的风险。因此,如果您在生产中禁用了断言,则必须运行两次测试。我提倡使用断言,但在所有构建中(包括生产)都启用它们。
            猜你喜欢
            • 2011-03-06
            • 1970-01-01
            • 2010-09-05
            • 2010-09-05
            • 2010-10-08
            • 2011-07-18
            • 2010-09-07
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多