为什么我们不能在公共方法中使用断言?
我曾在某处阅读过:
"在公共方法中,assert 不合适,因为该方法保证始终执行参数检查。无论是否启用断言,公共方法都必须检查其参数。此外,断言结构不会抛出指定类型的异常,它只能抛出 AssertionError。"
那么,这对私有方法也适用吗?
我没有完全理解上述说法。
为什么我们不能在公共方法中使用断言?
我曾在某处阅读过:
"在公共方法中,assert 不合适,因为该方法保证始终执行参数检查。无论是否启用断言,公共方法都必须检查其参数。此外,断言结构不会抛出指定类型的异常,它只能抛出 AssertionError。"
那么,这对私有方法也适用吗?
我没有完全理解上述说法。
重要的区别在于,您认为错误值是由:
a) 编程错误导致需要在代码中修复。
b) 输入错误无法在代码中预防,需要在运行时进行处理。
对于第一种情况,应使用assert,因为程序代码需要进行修复。如果是后一种情况,则应使用适当的运行时或检查异常。
我认为assertions用于检测编程错误,而不是用户/外部输入。也许作者将公共方法误认为是外部输入,当你有公共方法并非由外部输入调用时会出现这种情况。
我会使用assertions来检查参数以检测编程错误。在我看来,这通常是它们最好的用途。相比之下,私有方法只能由同一类中的代码调用,并且您应该期望它们经过很好的单元测试并具有有限的可能的访问/用途。
我发现您更有可能通过公共接口出现编程错误,因为不同的人会做出不同的假设(assertions是文档和检查假设的好方法)。内部检查不像您期望的那样有用,因为如果没有编写整个内部代码库,同一程序员将可以访问内部代码。
断言(Assertions)不应用于公共方法中对参数进行检查,原因如下:
示例:
/**
* @throws ArithmeticException if divisor is zero
*/
public void int divide(int divisor) {
if (divisor == 0) {
throw new ArithmeticException("Cannot divide by zero");
}
...
}
如果您在这里使用了一个断言,它可能会被关闭,并且会抛出一个不太有用和没有信息的AssertionFailedException
异常。
我给出的回答并不完全准确。当然,您可以在公共方法(或任何您喜欢的地方)使用assert。
重点更多地在于您应该做什么或不应该做什么。我自己非常理解其他人关于何时应该或不应该使用断言的回答。
但是我必须承认,我从来没有使用过断言,并且很少看到代码中有断言。我只工作了几年,但在我工作的4个完全不同的公司中,没有一个公司在代码中使用了断言。无论是用于预订航班的超过1000万行代码的Web应用程序,还是用于控制航天器的控制中心,用于管理大型超市或缺陷跟踪器的软件。它们都没有使用断言。所有公司都有不同的需求和方法。没有使用断言。
对我来说,原因很简单。这里的人们说断言是用于调试的。没问题。而且您可以停用它们以提高速度。一开始没问题。程序越复杂,您花费的时间就越长。即使代码覆盖率达到100%,即使进行了广泛的集成和验证测试,某些错误也只能在生产环境中发现。仅仅因为您的用户最终会比您更多地使用应用程序。而且他们不会像您一样使用它。
有趣的是,因为这样的代码,我们在生产日志中仍然看到堆栈跟踪:
catch (MyException e) {
logger.war("This should never happen",e);
}
总体来说,这似乎是可行的。虽然有些情况下可能会很有用。
考虑到我们可能想要对已知存在的元素执行数据库更新
操作。那么查看例程是否成功可能会很有用,例如:
public void update(Object o) {
int nUpdatedObjects = dao.update(o);
assert(nUpdatedObjects == 1)
}
dao
层。assert()
来验证方法参数是否合理。(这很有用,但只是assert()
所擅长的一部分,正如你所指出的那样。 :) - sarnold断言是用于调试的;公共方法通常不应该通过调试断言来验证事物,而应该通过进行适当的参数检查并抛出适当的异常来验证。如果您想要验证内部对象状态,则可以使用它,但不要用于验证参数。
这个禁令只适用于公共接口。
来自http://download.oracle.com/javase/6/docs/technotes/guides/language/assert.html#preconditions:
按照惯例,公共方法的前提条件是通过显式检查来强制执行的,这些检查会抛出特定的指定异常。
基本上,公共接口保证检查前提条件并抛出特定异常而不是 AssertionError。
对于所有其他情况,断言非常有价值,并且是“按合同编程”的基石。请参见http://java.sun.com/developer/technicalArticles/JavaLP/assertions以获得良好的介绍。
Java 有未检查异常是有原因的--这些异常通常不应被捕获,因为它们可能会导致灾难性的故障。任何内存分配都可能抛出 OutOfMemoryError 异常。一个失败的断言(客户端代码中提供无效参数给我们的 API 的错误)同样具有严重后果。确实可以关闭断言,但永远不应该这样做。如果你担心运行你的代码的人会关闭断言,你可以自己创建一个无法关闭的简单断言类。使用断言的原则没有改变。你需要考虑的关于断言的唯一问题是接口的性能契约。请注意,这也可以是“隐式”的契约(即明显的实现应该非常快,而花费一分钟则超出了暗示的性能契约)。所以要确保在性能契约下验证你的断言是可接受的。公共方法可以被任何人调用,并且不能控制传递的参数值。
如果假设在公共方法中使用断言验证输入参数值,那么如果禁用了断言,这些检查(验证)可能不会发生(或执行),我们将从方法执行中得到不希望的结果。为避免这种不良结果,我们不应使用断言来验证公共方法参数值。
现在你可能会问为什么要使用断言来验证私有方法参数值?
原因是私有方法可以从定义它的类中调用(从实例方法或静态主方法中)。事实上,类的开发者知道私有方法的全部细节-它的功能、如何调用以及要传递的参数值。因此,私有方法参数值可以通过断言安全地进行验证。