这是Java断言的过度使用吗?

时间:2014-09-17 11:47:41

标签: java assert

我试图掌握在Java中使用assert关键字的方法。据我所知,正确的情况是验证应该永远属实的事情。

我担心我过度使用断言。

以下是一个示例:

private BodyParams() {
    assert revokedDoc != null : "revokedDoc must not be null";
    assert revokedDoc.getStatus() == DocumentStatus.Revoked : "document is not revoked";
    assert !isBlank(revokedDoc.getDocType()) : "docType should not be blank";
    assert revokedDoc.getIssuedDate() != null : "doc should have issue date";
    assert revokedDoc.getSendingOrg() != null 
            && !isBlank(revokedDoc.getSendingOrg().getName()) 
            : "sending ord should exists and name should ne populated";

    if (registeredUser) {
        assert revokedDoc.getOwner() != null 
                && !isBlank(revokedDoc.getOwner().getFirstName()) 
                : "owner should exists and first name should be populated";

        this.ownerFirstName = revokedDoc.getOwner().getFirstName();
        this.docUrl = Application.PUBLIC_HOSTNAME 
                + controllers.routes.DocumentActions.viewDocument(
                    revokedDoc.getId()
                ).url();

    } else {

        this.ownerFirstName = null;
        this.docUrl = null;

    }

    if (revokedDoc.getStatus() == DocumentStatus.Available) {
        assert !isBlank(revokedDoc.getFriendlyName()) 
                : "friendly name should not be blank for picked-up docs";

        this.friendlyName = revokedDoc.getFriendlyName();

    } else {
        this.friendlyName = null;
    }

    this.docType = revokedDoc.getDocType();

    this.issueDate = revokedDoc.getIssuedDate();

    this.issuerName = revokedDoc.getSendingOrg().getName();
}

在此示例中,假设revokedDoc字段来自数据库,并在插入时执行了正确的验证。这些断言测试了这个假设。这有点过头了吗?

编辑我应该提到这只适用于开发代码。生产中不会启用断言。我使用断言来确保来自生产中受信任来源的已知良好数据的数据在开发中表现自己

5 个答案:

答案 0 :(得分:3)

Assert非常有用,在库或模块中应该始终为true 。它旨在验证代码中的不变量(控制流,内部等),并且使用它来强制正确使用代码是一个坏主意(你有例外)。

因此,您的公共接口永远不应该基于断言:当您有一个公共方法并且想要检查输入参数时,通常最好抛出IllegalArgumentException

Here是一些关于断言的好文档。

在您的示例中,我认为您应该使用异常而不是断言。对来自数据库的数据执行一些有效性检查并不是一个坏主意(即使它已经在输入上验证),但是在生产代码中可能会禁用断言,您必须考虑如何处理这种格式错误的内容。

答案 1 :(得分:3)

看起来不对劲。为简化起见,可能会出现两大类问题,需要检查变量的有效性:

  • 您的方法接收或使用的参数可能不是您所期望的,并且您的方法应该进行适当的参数检查,并在需要时抛出IllegalArgumentExceptionNullPointerException或其他任何内容。示例:客户端代码已传入null参数,并且您无法控制该代码
  • 您的方法使用了一些类内部,您应该进行适当的单元测试,以确保这些内部始终是一致的,并且您的方法可以使用它们而无需额外的检查。

在您的情况下,创建revokeDoc对象的方法应该确保它在创建后处于有效状态,否则采取适当的操作,例如抛出异常并回滚任何更改。这样你的BodyParams方法可以只使用该对象而没有所有那些在错误的时间使代码混乱的断言:如果revokeDoc不一致,那么对它做一些事情可能已经太晚了早先检测到。

相关文章:Exception Vs Assertion

答案 2 :(得分:2)

这可能是一个固执己见的问题。但是,我会选择以下事项来决定:

  1. 此方法是否暴露给外部世界(通过接口,JAR文件,用户输入字段或您可以从不在您控件中的源获取输入的任何地方) - 然后我应该有一个有效的实际检查结果在一个例外中。
  2. 我是否依赖断言来正确执行代码?如果是这样,我不应该。在运行时,断言意味着被禁用。
  3. 这个断言总是如此吗?如果是的话,我是否会在关闭案例中使用它进行调试 - 然后是的,使用断言代替代码注释。当事情变坏时,启用断言并找出错误。

答案 3 :(得分:1)

您需要考虑两种情况:开发代码生产代码

由于Java的assert语句默认是禁用的(并且通过检查通过将-ea传递给VM而启用的全局静态标志来增加很少的开销),我不会考虑这种开销,因为它可以帮助您在开发阶段早期检测到问题(假设您已在开发环境中启用了断言)。

另一方面,你说" ...插入时进行了正确的验证......" - 那么,你怎么知道数据库中的值没有同时改变?如果安全对您的系统很重要(我只是假设它),一个基本模式是您不能相信从外部获得的任何东西。意味着,验证您从数据库中读取的值 - 但是,在这种情况下,assert不是正确的工具。使用正常的验证代码和例外。

答案 4 :(得分:0)

根据OO metology的最佳做法是检查你收到的params。并为其他人创建常客检查。在你的情况下你应该得到这样的东西:

private BodyParams(revokedDoc)
[...]
asserts of the params

if(isBlank(revokedDoc.....)

所有资产看起来都很好,并且是确保方法具备所有内容的方法。但他们应该做出错误的帮助,而不是让你的程序运作。