Java 断言是否损坏?

在浏览问题时,我最近在Java中发现了关键字。起初,我很兴奋。一些我不知道的有用的东西!一种更有效的方法来检查输入参数的有效性!耶学习!assert

但后来我仔细看了一眼,我的热情与其说是“缓和”,不如说是“完全扼杀”,因为一个简单的事实是:你可以把断言关掉。

这听起来像是一场噩梦。如果我断言我不希望代码继续运行,如果输入是,我为什么要忽略这个断言呢?这听起来像是,如果我正在调试一段生产代码,并怀疑可能被错误地传递了一个,但没有看到任何日志文件证据证明该断言被触发,我不能相信实际上发送了一个有效的值;我还必须说明断言可能已被完全关闭的可能性。listOfStuffnulllistOfStuffnulllistOfStuff

这假设我是调试代码的人。不熟悉断言的人可能会看到这一点,并假设(非常合理地)如果断言消息没有出现在日志中,则可能不是问题所在。如果你第一次遇到是在野外,你会想到它可以完全关闭吗?毕竟,这并不是说有一个命令行选项可以让你禁用try/catch块。listOfStuffassert

所有这些都把我带到了我的问题(这是一个问题,而不是咆哮的借口!我保证!

我错过了什么?

有没有一些细微差别使Java的实现比我给予它的信任更有用?在某些情况下,从命令行启用/禁用它的能力是否真的非常有价值?当我设想在生产代码中使用它来代替像这样的语句时,我是否以某种方式误解了它?assertif (listOfStuff == null) barf();

我只是觉得这里有一些重要的东西,我没有得到。

*好的,从技术上讲,它们实际上是默认关闭的;你必须不厌其烦地打开它们。但是,您仍然可以完全淘汰它们。


编辑:要求开悟,接受开悟。

首先是调试工具的概念对于使其对我有意义有很长的路要走。assert

我仍然对在生产环境中禁用非平凡私有方法的输入检查的概念提出异议,因为开发人员认为糟糕的输入是不可能的。根据我的经验,成熟的生产代码是一个疯狂、庞大的东西,由具有不同程度技能的人多年来开发,针对的是不同程度的理智的快速变化的需求。即使糟糕的输入真的是不可能的,六个月后草率的维护编码也可以改变这一点。gustafc提供的链接(谢谢!)包括以下示例:

assert interval > 0 && interval <= 1000/MAX_REFRESH_RATE : interval;

在生产中禁用如此简单的检查让我感到愚蠢乐观。但是,这是编码理念的差异,而不是损坏的功能。

此外,我绝对可以看到这样的东西的价值:

assert reallyExpensiveSanityCheck(someObject) : someObject;

我感谢所有花时间帮助我理解此功能的人;非常感谢。


答案 1

assert合同设计的一个有用的部分。在这种情况下,断言可用于:

  • 前提条件检查。
  • 条件后检查。
  • 中间结果检查。
  • 类不变检查。

断言的评估成本可能很高(例如,以类不变量为例,在调用类的任何公共方法之前和之后必须保持)。断言通常只在调试版本中和用于测试目的时使用;你断言不可能发生的事情 - 这些事情是有错误的同义词。断言根据代码本身的语义验证代码。

断言不是输入验证机制。当输入在生产环境中可能确实正确或错误时,即对于输入- 输出层,请使用其他方法,例如异常或良好的旧条件检查。


答案 2

Java的断言并不是真正用于参数验证的 - 它特别指出,断言不能用于亲爱的旧的TravilArgumentException(也不是在C语言中使用它们的方式)。它们更多地用于内部验证,让您对代码做出假设,而从查看代码来看并不明显。

至于关闭它们,你也可以在C(++)中这样做,只是如果有人有一个无断言的构建,他们没有办法打开它。在 Java 中,只需使用适当的 VM 参数重新启动应用即可。


推荐