我有一个简单的setter方法的属性和空是不适合这个特定的属性。在这种情况下,我总是被撕裂:我应该抛出一个IllegalArgumentException,还是一个NullPointerException?从javadocs来看,两者都很合适。是否存在某种公认的标准?或者这只是其中一件事,你应该做任何你喜欢做的事情,两种都是正确的?
当前回答
公认的做法是使用IllegalArgumentException(字符串消息)来声明一个参数是无效的,并给出尽可能多的细节…所以说,一个参数被发现是空的,而异常是非空的,你会这样做:
if( variable == null )
throw new IllegalArgumentException("The object 'variable' cannot be null");
你几乎没有理由隐式地使用“NullPointerException”。NullPointerException是当您试图在空引用(如toString())上执行代码时由Java虚拟机抛出的异常。
其他回答
在这种情况下,IllegalArgumentException使用API向用户传达了“不应该为空”的明确信息。正如其他论坛用户指出的那样,只要你使用API向用户传达正确的信息,你就可以使用NPE。
GaryF和tweak放弃了“有效Java”(我发誓)的参考,建议使用NPE。看看其他好的API是如何构造的,这是了解如何构造你的API的最好方法。
Another good example is to look at the Spring APIs. For example, org.springframework.beans.BeanUtils.instantiateClass(Constructor ctor, Object[] args) has a Assert.notNull(ctor, "Constructor must not be null") line. org.springframework.util.Assert.notNull(Object object, String message) method checks to see if the argument (object) passed in is null and if it is it throws a new IllegalArgumentException(message) which is then caught in the org.springframework.beans.BeanUtils.instantiateClass(...) method.
您应该抛出一个IllegalArgumentException,因为这将使程序员清楚地知道他做了一些无效的事情。开发人员太习惯于看到VM抛出的NPE,以至于任何程序员都不会立即意识到自己的错误,并开始随机查看,或者更糟糕的是,指责你的代码“有bug”。
以上两个例外的链接定义如下 IllegalArgumentException:抛出该异常,表示方法被传递了一个非法或不适当的参数。 NullPointerException:当应用程序试图在需要对象的情况下使用null时抛出。
这里最大的区别是IllegalArgumentException应该在检查方法的参数是否有效时使用。当一个对象被“使用”为空时,就应该使用NullPointerException。
我希望这能帮助你正确看待这两者。
实际上,在我看来,抛出IllegalArgumentException或NullPointerException的问题只是对Java中不完全理解异常处理的少数人的“圣战”。一般来说,规则很简单,如下:
argument constraint violations must be indicated as fast as possible (-> fast fail), in order to avoid illegal states which are much harder to debug in case of an invalid null pointer for whatever reason, throw NullPointerException in case of an illegal array/collection index, throw ArrayIndexOutOfBounds in case of a negative array/collection size, throw NegativeArraySizeException in case of an illegal argument that is not covered by the above, and for which you don't have another more specific exception type, throw IllegalArgumentException as a wastebasket on the other hand, in case of a constraint violation WITHIN A FIELD that could not be avoided by fast fail for some valid reason, catch and rethrow as IllegalStateException or a more specific checked exception. Never let pass the original NullPointerException, ArrayIndexOutOfBounds, etc in this case!
至少有三个非常好的理由反对将所有类型的参数约束违反映射到IllegalArgumentException,第三个理由可能非常严重,以至于标志着这种做法的糟糕风格:
(1) A programmer cannot a safely assume that all cases of argument constraint violations result in IllegalArgumentException, because the large majority of standard classes use this exception rather as a wastebasket if there is no more specific kind of exception available. Trying to map all cases of argument constraint violations to IllegalArgumentException in your API only leads to programmer frustration using your classes, as the standard libraries mostly follow different rules that violate yours, and most of your API users will use them as well!
(2) Mapping the exceptions actually results in a different kind of anomaly, caused by single inheritance: All Java exceptions are classes, and therefore support single inheritance only. Therefore, there is no way to create an exception that is truly say both a NullPointerException and an IllegalArgumentException, as subclasses can only inherit from one or the other. Throwing an IllegalArgumentException in case of a null argument therefore makes it harder for API users to distinguish between problems whenever a program tries to programmatically correct the problem, for example by feeding default values into a call repeat!
(3) Mapping actually creates the danger of bug masking: In order to map argument constraint violations into IllegalArgumentException, you'll need to code an outer try-catch within every method that has any constrained arguments. However, simply catching RuntimeException in this catch block is out of the question, because that risks mapping documented RuntimeExceptions thrown by libery methods used within yours into IllegalArgumentException, even if they are no caused by argument constraint violations. So you need to be very specific, but even that effort doesn't protect you from the case that you accidentally map an undocumented runtime exception of another API (i.e. a bug) into an IllegalArgumentException of your API. Even the most careful mapping therefore risks masking programming errors of other library makers as argument constraint violations of your method's users, which is simply hillareous behavior!
With the standard practice on the other hand, the rules stay simple, and exception causes stay unmasked and specific. For the method caller, the rules are easy as well: - if you encounter a documented runtime exception of any kind because you passed an illegal value, either repeat the call with a default (for this specific exceptions are neccessary), or correct your code - if on the other hand you enccounter a runtime exception that is not documented to happen for a given set of arguments, file a bug report to the method's makers to ensure that either their code or their documentation is fixed.
作为一个主观问题,这应该是封闭的,但它仍然是开放的:
这是我以前工作的地方使用的内部政策的一部分,效果非常好。这些都是我的记忆,所以我不记得确切的措辞。值得注意的是,他们没有使用受控异常,但这超出了问题的范围。他们使用的未检查异常主要分为3类。
NullPointerException:不故意抛出。npe只有在解引用空引用时才会被VM抛出。要尽一切可能的努力确保这些错误永远不会被抛出。@Nullable和@NotNull应该与代码分析工具一起使用来发现这些错误。
IllegalArgumentException:当函数的参数不符合公共文档时抛出,这样就可以根据传入的参数识别和描述错误。OP的情况就属于这一类。
IllegalStateException:当调用函数时,其实参在传递时是意外的,或者与方法所属对象的状态不兼容时抛出。
例如,在有长度的事物中使用IndexOutOfBoundsException的两个内部版本。一个是IllegalStateException的子类,在索引大于长度时使用。另一个是IllegalArgumentException的子类,用于索引为负的情况。这是因为您可以向对象添加更多的项,并且参数将是有效的,而负数永远无效。
正如我所说,这个系统工作得非常好,有人解释了为什么会有这样的区别:“根据错误的类型,你很容易就能弄清楚该怎么做。即使您无法真正找出出错的地方,也可以找出在哪里捕获错误并创建额外的调试信息。”
NullPointerException:处理Null情况或放入断言,这样NPE就不会被抛出。如果你输入的断言只是另外两种类型中的一种。如果可能,继续调试,就像断言一开始就在那里一样。
IllegalArgumentException:你的调用站点有错误。如果传入的值来自另一个函数,请查明为什么接收到不正确的值。如果传入一个参数,则会在调用堆栈中进行错误检查,直到找到没有返回预期值的函数。
您没有按照正确的顺序调用函数。如果您正在使用其中一个参数,请检查它们并抛出IllegalArgumentException描述该问题。然后,您可以在堆栈上传播腮部,直到找到问题。
不管怎样,他的观点是你只能把IllegalArgumentAssertions复制到堆栈上。您无法将illegalstateexception或nullpointerexception传播到堆栈上,因为它们与您的函数有关。
推荐文章
- Intellij IDEA Java类在保存时不能自动编译
- 何时使用Mockito.verify()?
- 在maven中安装mvn到底做什么
- 不可变与不可修改的集合
- 如何在JSON中使用杰克逊更改字段名
- GSON -日期格式
- 如何从线程捕获异常
- 无法解析主机"<URL here>"没有与主机名关联的地址
- getActivity()在Fragment函数中返回null
- 如何在Java中打印二叉树图?
- String.format()在Java中格式化双重格式
- com.jcraft.jsch.JSchException: UnknownHostKey
- Java中的操作符重载
- 如何加速gwt编译器?
- 在Hibernate中重新连接分离对象的正确方法是什么?