论断言和例外; Java的
在这个特定的场景中,断言比exception更合适吗?
据我所知,当程序FUBAR达到无法恢复并退出的程度时,应使用assert。
我还被告知要始终抛出exception以便清晰和错误消息处理。
每次使用时间之间是否存在细微差别? 有没有一个例子,必须无条件地使用断言代替例外?
public void subscribe(DataConsumer c) throws IllegalArgumentException { if (c == null) { // Almost certainly FUBAR throw new IllegalArgumentException("Can't subscribe null as a DataConsumer. Object not initialized"); } if (dataConsumerList == null) { // Definetely FUBAR throw new IllegalArgumentException("Nothing to subscribe to. DataConsumerList is null"); } dataConsumerList.add(c); }
就个人而言,我并不热衷于使用断言来解决这类问题,因为它们可以被关闭。 有些地方在运行测试时使用断言,但为了速度而禁用它们进行生产。 对我来说,这就像正常进行驾驶考试一样,但是当你上高速公路时,就要取下安全带。
当然,断言只会抛出exception。 如果你现在绝对想要关闭JVM,你需要使用像Runtime.halt
这样的东西。
所以我在这里是exception的粉丝,虽然我在给定null参数时通常使用NullPointerException
,并且如果dataConsumerList
是你的状态的一部分,那么我个人会使用IllegalStateException
来区分这种情况。 (遗憾的是,Java没有与.NET相同的ArgmentNullException
,给出了常见的检查。)
Guava有一个有用的Preconditions
类,可以让你更简洁地写出:
public void subscribe(DataConsumer c) throws IllegalArgumentException { Preconditions.checkNotNull(c, "Can't subscribe null as a DataConsumer. Object not initialized"); Preconditions.checkState(dataConsumerList != null, "Nothing to subscribe to. DataConsumerList is null"); dataConsumerList.add(c); }
一般规则(从这里复制)
断言应该保护开发人员的错误(并不总是显而易见的),例如使用指针尽管它是NULL。
exception是一种处理可能在运行时合法发生的错误的方法,例如尝试连接到某个服务器的失败(可能由于各种原因而无法响应)。
使用google-guava Preconditions.checkNotNull()类编写上述代码有一种更好的方法。
public void subscribe(DataConsumer c) throws IllegalArgumentException { checkNotNull(c, "Can't subscribe null as a DataConsumer. Object not initialized"); checkNotNull(dataConsumerList , "Nothing to subscribe to. DataConsumerList is null"); dataConsumerList.add(c); }
如果您可以用英语术语来表达,请使用assert作为“gotta”(Got to,Must)和“otta”的例外(应该是,应该)。
将断言用于显示停止,关键条件必须为true才能继续执行。 示例可能是分区正确发生(想想英特尔芯片浮点错误)或者在正确打开它之后数据库连接不为空。 如果发生了这些,则程序执行不应继续。
使用throw来解决您的方法可能遇到的可预见错误。 抛出是合同的一部分,向您和其他程序员声明可能遇到某些类型的错误(并且这不是您的责任)。
在您的示例中,我的猜测是在正常情况下永远不会发生null使用者或空列表。 如果我的猜测是正确的,那么你会想在这里使用一个断言,声明subscribe()将处理它。
如果我的猜测是错误的并且发生了一个空的消费者,比如50次中的1次,则抛出会更好,你会声明subscribe()与调用方法形成一个契约,从而调用方法处理错误。
Java技术说明使用断言编程包含有关用法的显式行:
不要在公共方法中使用断言进行参数检查。
这应该是你的问题的一个非常确定的答案。