为什么我们不能将断言用于公共方法?

时间:2011-03-23 11:49:27

标签: java assert public-method

为什么我们不能将断言用于公共方法?

我在某处读过

  

“断言在公开场合不合适   方法因为方法保证   它将始终强制执行   参数检查。公共方法必须   检查它的参数是否   断言已启用。而且,   断言构造不会抛出   指定类型的异常。它   只能抛出AssertionError“。

那么,它也不适用于私人方法吗? 我不明白上述陈述

11 个答案:

答案 0 :(得分:24)

重要的区别在于您是否认为不正确的值是

的结果

a)应该在代码中修复的编程错误。

b)输入错误,无法在代码中阻止,而是需要在运行时处理。

对于第一种情况,您应该使用断言,因为程序代码需要修复。如果是后一种情况,则应使用适当的运行时或检查异常。


IMHO断言用于检测编程错误,而不是用户/外部输入。当你有一个不被外部输入调用的公共方法时,作者可能会将公共方法混淆为外部输入。

我会使用断言来检查参数以检测编程错误。恕我直言,这通常是他们最好的用途。相比之下,私有方法只能由同一个类中的代码调用,您应该期望它们能够很好地进行单元测试并限制可能的访问/使用。

我发现你更有可能通过公共接口出现编程错误,因为不同的人做出不同的假设(断言是记录和检查假设的好方法)内部检查没有你期望同一个程序员那么有用如果没有编写整个内部代码库,则可以访问内部代码。

答案 1 :(得分:15)

由于以下原因,断言不应用于检查公共方法中的参数:

  • 断言可以被禁用,参数检查应该从不被禁用,因为它们是方法与其呼叫者的合同的一部分
  • 断言失败不会为无效参数抛出适当的异常。

示例:

    /**
     * @throws ArithmeticException if divisor is zero
     */ 
    public void int divide(int divisor) {
        if (divisor == 0) {
            throw new ArithmeticException("Cannot divide by zero");
        }
        ...
    }

如果你在这里使用了一个断言,它可能会被关闭,它会抛出一个AssertionFailedException,这是无益的,没有信息。

答案 2 :(得分:3)

就目前而言,你引用的句子是无稽之谈,我相信。

可以肯定的是,断言不是用于验证参数。

但是在每个非平凡的程序中都有(或者应该)有一些不变量,这就是断言可以派上用场的地方。如果你能在断言中表达不变量,请不论这种方法是否公开都可以这样做。

然后,将发生以下其中一种情况:

a)一切都很好 b)在运行时,程序因未完成的断言而失败。如果断言是正确的,则违反了不变量,您有机会找出原因并修复错误(或重新考虑您的设计)。

答案 3 :(得分:1)

总的来说,这似乎是合理的。虽然在某些情况下这可能有用。

考虑到我们可能希望对我们知道存在的元素执行database update操作。然后查看例程是否成功可能是有用的,例如:

public void update(Object o) {
   int nUpdatedObjects = dao.update(o);
   assert(nUpdatedObjects == 1)
}

在这种情况下,它使用fail fast principle投放到validate dao图层。

答案 4 :(得分:1)

断言用于调试;公共方法通常不应该通过调试断言验证事物,而是通过进行适当的参数检查并抛出适当的异常。如果要验证内部对象状态,则可以使用它,但不能验证参数。

答案 5 :(得分:1)

我给出的答案并不完全正确。当然,您可以在公共方法中使用assert(或者您喜欢的任何地方)。

关键在于你应该做什么或不做什么。我自己完全理解其他人对你何时应该或不应该使用断言的回应。

但我必须承认我从不使用断言,而且我很少在代码中看到断言。我工作了几年,但在我工作的4家完全不同的公司中,代码中没有断言。无论是预订航班的超过1000万行代码网络应用程序,航天器控制中心,管理大型超市的软件还是错误跟踪器。他们都没有使用断言。所有公司都有不同的需求和方法。没有使用断言。

对我来说原因很简单。这里的人说断言是为了调试。没关系。并且您可以停用它们以提高速度。那太好了......起初。程序越复杂,调试时间就越多。还有一些错误,即使有100%的代码覆盖率,即使进行了大量的集成和验证测试,您也只能在生产中找到它们。仅仅因为您的用户最终使用的应用程序比您更多。他们不会像你一样使用它。

这很有趣,因为在生产日志中,我们一直看到来自这样的代码的堆栈跟踪:

catch (MyException e) {
  logger.war("This should never happen",e);
}

这意味着你永远不知道生产中会发生什么。

如果您有机会进行检查,请执行此操作。当然日志注释比这里有用更有趣,最好让异常弹出。

在所有情况下都不要将其作为在生产中禁用的断言。因为它没用。使其成为引发异常的正常代码。确保在适当的情况下记录它。确保UI上显示错误。并确保您能够获取异常和日志以进行调查。

重要的是,有一天,某些用户会做出警告弹出的事情。因为编写错误的代码或任何东西,你会看到它。这意味着,不是花费2天时间找到为什么程序会有这种奇怪的行为,你就可以在起点使用完整的堆栈跟踪并在2小时内纠正问题。

使用禁用断言的检查与根本不检查相同。这是你必须编写,阅读和维护的代码......什么都不做。我理解整个性能论证,即生产中的断言会减慢速度。是的,在少数情况下,存在性能问题。在大多数情况下,无论如何你都几乎没有任何收获,并且失去了宝贵的暗示。

答案 6 :(得分:1)

这可能是Java SE指南"Programming with assertions."

中的原始来源
  

不要使用断言来检查   公共方法的参数。一个   断言是不恰当的,因为   方法保证它将永远   强制执行参数检查。它必须   检查它的参数是否   断言已启用。而且,   断言构造不会抛出   指定类型的异常。它   只能抛出一个AssertionError。

这不会禁止公共方法中的断言。它仅限于检查公共方法参数。

断言测试不变量。类控制发送到其私有方法的实际参数,并且可以保证不变量。类不控制发送到公共方法的实际参数,并且如果违反了前提条件,则应抛出异常,即使断言断言也是如此。

有关何时使用断言的更多详细信息是here

答案 7 :(得分:1)

在公共方法中使用断言没有任何错误。它们可以用来检查某些不变量(你认为是真的),关于你正在调用方法的对象或类 - 实际上是真的。

例如,您可以在构建器的public build()方法中使用断言,以确保构建器已由我自己的内部代码在该类中正确初始化(因为我有一些重载的构造函数)。

但是你不应该做的是使用断言来检查公共方法的ARGUMENTS。一个重要的区别。我认为这里的其他答案已经清楚地解释了原因,所以我不会重复任何事情。

答案 8 :(得分:0)

这个想法是你不知道谁将使用你的公共方法。因此,您必须通过正常检查来防止不当使用。

另一方面,私有方法应该由当前团队的开发人员单独使用,因此检查不是强制性的(但仍然建议恕我直言)。

因此,为了检查私有方法的参数有效性,断言应该足够了。

答案 9 :(得分:0)

此禁令仅适用于公共接口。

来自http://download.oracle.com/javase/6/docs/technotes/guides/language/assert.html#preconditions

  

按照惯例,公共方法的前提条件通过显式检查来强制执行,这些检查会抛出特定的指定异常。

基本上,惯例是公共接口保证检查前提条件并抛出特定异常而不是AssertionError。

对于所有其他情况,断言非常有价值,并且是“按合同编程”的基石。有关详细介绍,请参阅http://java.sun.com/developer/technicalArticles/JavaLP/assertions

  1. Java出于某种原因取消选中异常 - 这些都是大量灾难性的失败,通常不应该被捕获。任何内存分配都可能抛出OutOfMemoryError。失败的断言(客户端代码中的错误,为我们的API提供了无效的参数)同样具有灾难性。

  2. 确实可以关闭断言 。但是,永远不应该这样做。只是不要这样做。如果您擅长运行代码的人将关闭断言,您可以随时创建一个无法关闭的简单断言类。使用断言的原则没有改变。

  3. 您应该考虑的断言的唯一内容是接口上的性能合同。请注意,这也可能是一个“隐含”的合同(即,当一个明显的实施应该非常快,一分钟超出隐含的性能合同时)。因此,请确保根据履约合同验证您的断言是否可以接受。

答案 10 :(得分:0)

任何人都可以调用公共方法,并且无法控制可以作为参数值传递的内容。

如果在public方法中假设我们使用断言验证了输入参数值,那么如果断言被禁用,那么这些检查(验证)可能不会发生(或执行),并且我们会从方法中获得不良结果为了避免这种不良结果,我们不应该使用断言来验证公共方法参数值。

现在你脑海中可能出现的问题是为什么使用断言来验证私有方法参数值?

嗯,原因是私有方法可以从定义的类中调用(从实例方法或静态main方法)。类infact的开发人员知道私有方法的一切 - 它做什么,如何调用它以及要传递的参数值。可以使用断言安全地验证私有方法参数值。