使用Assert作为函数参数来强制执行其有效性是一种好习惯。我正在浏览Spring Framework的源代码,我注意到他们经常使用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);
}
}
}
答案 0 :(得分:56)
原则上,assertions与许多其他运行时检查没有什么不同。
例如,Java绑定 - 在运行时检查所有数组访问。这会让事情变慢吗?是。这有益吗?绝对!一旦发生越界违规,就会抛出异常并且程序员会收到任何可能的错误警报!未对数组访问进行绑定检查的其他系统中的行为更加难以置信! (通常带来灾难性的后果!)。
断言,无论您使用图书馆还是语言支持,在精神上都是相似的。有性能成本,但绝对值得。事实上,断言更有价值,因为它是明确的,并且它传达了更高层次的概念。
正确使用,可以最大限度地降低性能成本,并为客户(将尽快捕获合同违规)和开发人员(因为合同自我执行和自我记录),最大化。
另一种看待它的方法是将断言视为“主动评论”。没有人认为评论是有用的,但它们是被动的;在计算上他们什么都不做。通过将一些概念描述为断言而不是注释,它们变为活动。他们实际上必须在运行时保持;违规行为将被抓获。
答案 1 :(得分:27)
这些断言是由库提供的,与内置的assert
关键字不同。
这里有一点不同:assert
默认情况下不运行(它们必须使用-ea
参数启用),而Assert
类提供的断言不能被禁用。
在我看来(对于它的价值而言),这与验证参数的方法一样好。如果您使用内置断言作为问题标题暗示,我会反对它,因为必须检查不应该是可移除的。但这种方式只是简写:
public static ParsedSql parseSqlStatement(String sql) {
if (sql == null)
throw new IllegalArgumentException("SQL must not be null");
...
}
......这在公共方法中总是很好的做法。
内置的断言样式对条件应始终为true的情况或私有方法更有用。 language guide introducing assertions有一些很好的指导方针,基本上就是我刚才所描述的。
答案 2 :(得分:18)
是的,这是一种很好的做法。
在Spring的情况下,它特别重要,因为检查是验证通常来自XML连线文件的属性设置等。换句话说,他们正在验证webapp的配置。如果你做过任何严肃的基于Spring的开发,当你犯一个愚蠢的配置错误时,那些验证检查将为你节省数小时的调试时间。
但请注意,名为Assert
的库类与用于定义Java断言的Java assert
关键字之间存在巨大差异。后一种形式的断言可以在应用程序启动时关闭,不应该用于您总是希望发生的参数验证检查。显然,Spring设计师认为关闭webapp配置健全性检查是一个非常糟糕的主意......我同意。
更新
在Java 7(及更高版本)中,java.util.Objects
类提供了requireNonNull
便捷方法来测试参数是否为null
并引发异常。你这样使用它:
SomeType t = ...
SomeType tChecked = Objects.requireNonNull(t);
或
SomeType tChecked = Objects.requireNonNull(t, "t should be non-null");
但请注意,此方法会引发NullPointerException
而不是IllegalArgumentException
。
答案 3 :(得分:6)
基于Sun的guide断言,你应该不在公共方法中使用断言来进行参数检查。
参数检查通常是方法的已发布规范(或契约)的一部分,无论是启用还是禁用断言,都必须遵守这些规范。
答案 4 :(得分:2)
在非常庞大且设计不良/维护的系统中,如果您希望提高方法的可预测性,例如6000行,并且公司中的任何人都不再理解它们,那么使用断言可能很有价值关键字导致开发环境爆炸,揭示错误。但是,如果你要在生产中实现这些断言,你可能会短路一个补丁,虽然可怕的想法,修复了一个问题。你想通过在开发环境中发现它而不是生产来修复那个坏补丁。因此,您可以在开发时打开断言,并在生产中将其关闭。
在开发时对assert关键字的另一个有效用法是将有效性检查插入到必须以亚毫秒次执行的算法中,并且与不可预测或未经测试的调用者隔离良好。在这种情况下,您可能无法负担保留生产中的有效性检查,尽管它在开发中仍然非常有用。另一方面,如果您要验证的参数来源不可预测或可能变得如此(例如,如果它部分由用户输入确定),您可能永远不会跳过支票,即使在生产中,也应该将性能作为开展业务的成本。 (在最后一种情况下,您可能不想使用断言。)但是,您应该选择断言以消除生产时有效性检查仅在分析后告诉您可以&# 39;承担开销。
答案 5 :(得分:1)
是的,这是个好主意。您正在强制执行接口或类的签约。如果存在合同违规,您希望尽快检测到它。等待的时间越长,结果越不可预测,诊断起来就越困难。
当您明确地进行此类检查时,您还应该提供一条信息消息,在日志文件中查看时可以提供有用的上下文来帮助找到根本原因,甚至只是意识到您对合同的内容做出了错误的假设。
答案 6 :(得分:0)
我将断言保留在已发布的二进制文件中,但修改后的行为:不调用abort,而是收集stacktrace。
此处有更多详情:http://blog.aplikacja.info/2011/10/assert-to-abort-or-not-to-abort-thats-the-question/