认定一个好的做法或不?
使用Assert作为函数参数来强制执行它是一个好习惯。 我正在浏览Spring框架的源代码,我注意到它们使用Assert.notNull
很多。 这是一个例子
public static ParsedSql parseSqlStatement(String sql) { Assert.notNull(sql, "SQL must not be null");}
这是另一个:
public NamedParameterJdbcTemplate(DataSource dataSource) { Assert.notNull(dataSource, "The [dataSource] argument cannot be null."); this .classicJdbcTemplate = new JdbcTemplate(dataSource); } public NamedParameterJdbcTemplate(JdbcOperations classicJdbcTemplate) { Assert.notNull(classicJdbcTemplate, "JdbcTemplate must not be null"); this .classicJdbcTemplate = classicJdbcTemplate; }
仅供参考, Assert.notNull
(不是assert
语句)在util类中定义如下:
public abstract class Assert { public static void notNull(Object object, String message) { if (object == null) { throw new IllegalArgumentException (message); } } }
原则上, 断言与许多其他运行时检查没有什么不同。
例如,Java在运行时绑定检查所有数组访问。 这会让事情变慢吗? 是。 这是有益的吗? 绝对! 一旦出现违规违规,就会抛出exception,并提醒程序员任何可能的错误! 数组访问没有被绑定的其他系统中的行为是非常不可预知的! (往往带来灾难性的后果!)。
断言,无论你使用图书馆还是语言支持,在精神上是相似的。 性能成本,但它是绝对值得的。 事实上,断言更为重要,因为它是明确的,它传递更高层次的概念。
如果使用得当,可以最大限度地降低性能成本,并且最大限度地为客户(他们将尽早而不是晚些时候捕获合同违规)和开发人员(因为合同是自我执行和自我logging )的价值。
另一种看待它的方法是将断言看作“积极的评论”。 没有人认为评论是有用的,但他们是被动的; 在计算上他们什么都不做。 通过将一些概念expression为断言而不是评论,它们变成活动的。 他们实际上必须在运行时间保持; 违规行为将被捕获。
另请参见: 使用断言进行编程的好处
这些断言是库提供的,与内置的assert
关键字不一样。
这里有一个区别:默认情况下, assert
s不运行(它们必须使用-ea
参数启用),而Assert
类提供的Assert
不能被禁用。
在我看来(这是值得的),这与validation参数一样好。 如果你使用内置的断言作为问题的标题,我会反驳它,因为必须的检查不应该是可移动的。 但是这种方式只是简单的:
public static ParsedSql parseSqlStatement(String sql) { if (sql == null) throw new IllegalArgumentException("SQL must not be null"); ... }
这在公共方法上总是很好的做法。
断言的内置样式对于条件始终为真的情况或私有方法更有用。 介绍断言的语言指南有一些很好的指导方针,基本上我刚刚描述过。
是的,这是很好的做法。
在Spring情况下,这一点尤其重要,因为这些检查正在validation属性设置等,这些属性设置通常来自XML配线文件。 换句话说,他们正在validationwebapp的configuration。 如果你曾经做过任何严肃的基于Spring的开发,那么当你犯了一个愚蠢的configuration错误时,这些validation检查将会为你节省数小时的debugging时间。
但请注意,名为Assert
的库类与用于定义Java断言的Java assert
关键字之间存在巨大差异。 后一种forms的断言可以在应用程序启动时closures,不应该用于您始终想要发生的参数validation检查。 显然,Spring的devise者认为closureswebappconfiguration的完整性检查是一个非常糟糕的主意……我同意。
UPDATE
在Java 7(及更高版本)中, java.util.Objects
类提供了一个requireNonNull
便捷方法来testing参数是否为null
并引发exception。 你这样使用它:
SomeType t = ... SomeType tChecked = Objects.requireNonNull(t);
要么
SomeType tChecked = Objects.requireNonNull(t, "t should be non-null");
但是,请注意,此方法引发NullPointerException
而不是IllegalArgumentException
。
基于Sun关于断言的指导 ,您不应该使用断言来进行公共方法中的参数检查。
参数检查通常是方法发布的规范(或契约)的一部分,无论断言是启用还是禁用,都必须遵守这些规范。
在非常大且devise不当的系统中,如果您希望提高6000线的可预测性,并且公司中没有人再理解这些方法,那么使用assert关键字来引发开发环境可能是有价值的炸毁,暴露的错误。 但是,如果你在生产中实施这些说法,你可能会缩短一个补丁,尽pipe可怕的构思,但修补了一个问题。 你想通过在开发环境中发现而不是在生产中修复那个不好的补丁。 所以你可以在开发时打开它,并在生产中closures它们。
开发时assert关键字的另一个有效用法是将有效性检查插入algorithm中,该algorithm必须在亚毫秒时间内执行,并且与不可预知的或未经testing的调用者完全隔离。 在这种情况下,您可能无法保留生产中的有效性检查,尽pipe它在开发中仍然非常有用。 另一方面,如果您正在validation的参数的来源是不可预知的,或者可能变得如此(例如,如果部分由用户input确定),则即使在生产中,也可能永远不能跳过检查,并且应该把业绩打到做生意的成本。 (在最后一种情况下,您可能不想使用断言)。但是, 只有在性能分析告诉您无法负担开销后,您才应该select断言来消除生产时间有效性检查。
是的,这是一个好主意。 你正在执行界面或类的承包。 如果违反合同,您希望尽快发现。 您等待的时间越长,结果越难以预测,诊断就越困难。
当你像这样明确地检查的时候,你也应该提供一个信息消息,当在日志文件中查看时,可以给出有用的上下文来帮助find根本原因,甚至只是意识到你对合同的错误假设。
我保持我的断言发布的二进制文件,但修改后的行为:中止不被调用,但堆栈跟踪收集。
更多细节在这里: http : //blog.aplikacja.info/2011/10/assert-to-abort-or-not-to-abort-thats-the-question/