陷阱使用断言进行参数或用户输入验证

StackOverflow 上偶尔会出现的问题是,使用 assert 验证提供给方法的参数是否合适,甚至是用户提供的输入。

简单的答案是它不合适。

更好的选择包括:

  • 使用自定义代码抛出 IllegalArgumentException。
  • 使用 Google Guava 库中提供的 Preconditions 方法。
  • 使用 Apache Commons Lang3 库中提供的 Validate 方法。

这就是 Java 语言规范(JLS 14.10,Java 8) 就此问题提出的建议:

通常,在程序开发和测试期间启用断言检查,并在部署时禁用断言检查以提高性能。

由于断言可能被禁用,因此程序不得假定将评估断言中包含的表达式。因此,这些布尔表达式通常应该没有副作用。评估此类布尔表达式不应影响评估完成后可见的任何状态。断言中包含的布尔表达式具有副作用并非违法,但通常不合适,因为它可能导致程序行为根据断言是启用还是禁用而变化。

鉴于此,断言不应用于公共方法中的参数检查。参数检查通常是方法合同的一部分,并且必须维护此合同是否启用断言。

使用断言进行参数检查的第二个问题是错误的参数应该导致适当的运行时异常(例如 IllegalArgumentExceptionArrayIndexOutOfBoundsExceptionNullPointerException)。断言失败不会引发适当的异常。同样,在公共方法上使用断言进行参数检查并不违法,但这通常是不合适的。AssertionError 的目的永远不会被捕获,但是有可能这样做,因此 try 语句的规则应该处理 try 块中出现的断言,类似于当前对 throw 语句的处理。