当前位置: 首页 > 知识库问答 >
问题:

积极抛出AssertionError是Java好做法吗?[复制]

习胤运
2023-03-14

通过阅读Joshua Bloch的“有效Java-第二版”,我在第152页偶然发现了以下代码

double apply(double x, double y) {
    switch(this) {
        case PLUS:   return x + y;
        case MINUS:  return x - y;
        case TIMES:  return x * y;
        case DIVIDE: return x / y;
    }
    throw new AssertionError("Unknown op: " + this);
}

现在让我感到困惑的是,断言错误被主动抛出。这被认为是好的做法吗?根据我的理解,断言用于不与代码交错,这样当java编程在没有启用断言的情况下启动并且因此不执行断言语句时,行为不会改变。如果我在运行程序时甚至不启用断言时会得到一个AssersisException,我会相当困惑。

尽管我知道示例情况可能会经常发生,但您分析了几个不同的选项,如果它们都不是,则应抛出异常。

那么在这里抛出AssertionException是好的做法,还是抛出一个不同的更好?如果是这样,哪个最适合?也许IllegalArgumentException

编辑澄清:我的问题不是关于我们是否应该在这里抛出一个Error,而是如果我们想抛出一个Exception或一个Error,应该是哪一个?主动抛出AssertionErrors是好的做法吗?留档说抛出表示一个断言失败了,所以我觉得我们不应该主动抛出它。对吗?

第二次编辑:明确的问题:主动抛出一个断言错误是好的做法,还是应该避免这种情况,即使这是可能的?(我猜阅读文档是后者)

共有3个答案

於德馨
2023-03-14

关于错误,Java教程指出:

第二种异常是错误。这些是应用程序外部的异常情况,应用程序通常无法预测或从中恢复。

此外,《使用断言编程指南》指出:

不要在公共方法中使用断言进行参数检查。

因此,我认为异常是检查此类情况的正确方法。

我建议使用< code > new UnsupportedOperationException(" Operator " name()"不受支持。");因为它更好地描述了我认为的问题(例如,开发人员添加了一个enum值,但忘记实现所需的case)。

然而,我认为这个示例案例应该使用<code>AbstractEnum</code>设计模式,而不是开关:

PLUS {
    double apply(double x, double y) {
        return x + y;
    }
},
MINUS {
    double apply(double x, double y) {
        return x - y;
    }
},
TIMES {
    double apply(double x, double y) {
        return x * y;
    }
},
DIVIDE {
    double apply(double x, double y) {
        return x / y;
    }
};

abstract double apply(double x, double y);

它不容易出错,因为在每个案例实现应用之前,此代码不会编译。

邓阳伯
2023-03-14

在我看来,断言错误在这里使用是不正确的。

在文档中,AssertionError扩展了基类< code>Error

Error 是 Throwable 的一个子类,它指示合理的应用程序不应尝试捕获的严重问题。

错误应该是致命的,而我希望您的程序能够处理此错误,并向用户显示有关未知操作的警告消息。

如果这里有任何问题,我希望抛出一个<code>UnsupportedOperationException

抛出以指示不支持请求的操作。

考虑以下情况:不是在计算器中,而是在任何使用ENUM的代码流中:

如果开发人员要向现有枚举添加新值,我不会期望利用此现有枚举的函数调用错误,仅仅因为不支持新值。

支阳波
2023-03-14

我同意Bloch先生的观点——替代选项(< code > IllegalArgumentException 、< code > IllegalStateException 和< code > UnsupportedOperationException )没有恰当地传达问题的严重性,呼叫者可能会错误地试图捕捉和处理这种情况。事实上,如果到达这一行,程序就会被破坏,唯一明智的做法就是退出。

这里的要点是枚举具有一组有限的值,因此应该不可能到达抛出线 - 只有在枚举的定义发生变化而没有修复此实例方法的情况下才会发生这种情况。抛出运行时异常表明调用方犯了一个错误,而实际上方法(和枚举)本身已经损坏。显式引发断言错误可正确指示此方法预期的不变量已被违反。

Guava有一篇有用的文章,详细介绍了何时引发不同类型的异常。他们写道:

常规断言是一种检查,只有在类本身(包含检查)以某种方式损坏时才应该失败。(在某些情况下,这可以扩展到包。)这些可以采取各种形式,包括后置条件、类不变量和内部先决条件(在非公共方法上)。

不可能的条件检查是不可能失败的检查,除非以后修改周围的代码,或者我们关于平台行为的最深层次的假设被严重违反。这些应该是不必要的,但通常是强制的,因为编译器无法识别语句无法访问,或者因为我们对编译器无法推断的控制流有所了解。

页面上说,断言错误是处理这些情况的推荐方法。它们的<code>Verify<code>类中的注释还提供了一些关于选择异常的有用见解。在<code>断言错误

至于< code>Error或< code>RuntimeException的具体问题,这并不重要(两者都是未检查的,因此可能会在调用堆栈中向上移动而不会被捕获),但是调用方更有可能尝试从< code>RuntimeException中恢复。在这种情况下使应用程序崩溃是一个特性,因为否则我们将继续运行(在这一点上)明显不正确的应用程序。调用者捕获并处理< code>AssertionError(或< code>Error或< code>Throwable)的可能性当然更小,但是调用者当然可以做他们想做的任何事情。

 类似资料:
  • 问题内容: 通过Joshua Bloch的“ Effective Java-Second Edition”,我偶然发现了第152页上的以下代码: 现在令我困惑的是,主动抛出该异常。那被认为是好的做法吗?据我所知,断言用于避免与代码发生干扰,因此在启动Java编程时未启用断言且因此未执行断言语句时,行为不会改变。如果我在没有启用断言的情况下运行程序时得到一个提示,我就会很困惑。 尽管我知道示例案例可

  • 问题内容: 我正在查看一位同事的代码,但遇到一段类似于以下代码的代码: 我相信没有必要,但我很难证明这一点。如果它更具体(,等等)可能很有意义,但是因为我认为这是不必要的。有人可以给我一些原因,这可能导致什么问题,以及为什么这是不好的做法?还是这个代码可以吗? 问题答案: 该声明是方法合同的一部分。定义合同时,您应始终尽可能 精确 。因此,说是个坏主意。 出于同样的原因,这是不好的做法,因为不好的

  • 我以为我有这个,但很明显我没有。从下表中,我试图显示那些做出了最积极贡献(文章)的用户,然后是那些没有做出积极贡献的用户。该表很简单,是文章Id,是显示文章是否被批准的状态。通过,不通过,然后是写文章的用户。 我正在努力实现的结果如下: 表 我想出的Sql 我没有太多的运气得到像我上面贴出来的结果。你能帮忙吗?这完全超出了我的范围。

  • 遵循Joshua Bloch的《有效的Java》中使用的风格,并与这个问题的答案一致,我过去在Java SE环境中使用AssertionErrors来表示不应该执行的代码路径。 看看JavaEE,EJB3.1规范说 如果bean方法遇到系统异常或错误,它应该简单地将错误从bean方法传播到容器(即,bean方法不必捕获异常)。 再往下一点,它说在非应用程序异常的情况下必须丢弃相关的EJB实例。据我

  • 问题内容: 我想知道使用语句退出循环而不是满足循环条件是否是“坏习惯” ? 我对Java和JVM的了解不足,无法知道如何处理循环,因此我想知道我是否通过这样做忽略了一些关键的事情。 这个问题的重点:是否有特定的性能开销? 问题答案: 好主啊 有时,可能会在满足整体要求的循环中发生某些事情,而不满足逻辑循环条件。在这种情况下,用于阻止您毫无意义地循环。 例 在此示例中更有意义的是。每次找到后都继续循

  • 假设我有一个类来为游戏中的一个项目建模,如下所示: (假设正确重写的和以比较内部枚举) 现在我想要一种方法来用中的getter来区分这些项:我应该返回还是名称?一般情况下返回是好的做法吗?或者是否有更好的方法来区分这些s?因为返回枚举类似于向我公开rep,而且我不希望我的同事直接使用来比较的 我想到的办法如下: 执行类似; 要执行; ; 要执行; 我不知道该怎么做,我希望有经验的程序员能给我一些启