Mik*_*one 535 java null exception nullpointerexception illegalargumentexception
我有一个简单的属性的setter方法,null不适合这个特定的属性.我总是在这种情况下被撕裂:我应该扔一个IllegalArgumentException,还是一个NullPointerException?从javadocs看,两者似乎都合适.有某种理解标准吗?或者这只是你应该做的任何事情之一,而且两者都是正确的?
Jas*_*hen 412
您应该使用IllegalArgumentException(IAE),而不是NullPointerException(NPE),原因如下:
首先,NPE JavaDoc明确列出了NPE合适的情况.请注意,如果使用不当,运行时会抛出所有这些内容null.相比之下,IAE JavaDoc还不能更清楚:"抛出来表示方法已被传递为非法或不恰当的参数." 是的,就是你!
其次,当您在堆栈跟踪中看到NPE时,您会假设什么?可能有人取消引用了一个null.当您看到IAE时,您认为堆栈顶部的方法的调用方传递了非法值.同样,后一种假设是正确的,前者是误导性的.
第三,由于IAE明确地设计用于验证参数,您必须将其视为异常的默认选择,那么为什么要选择NPE呢?当然不是出于不同的行为 - 您是否真的希望调用代码将IAE与IAE分开捕获并做一些不同的结果?您是否尝试传达更具体的错误消息?但是你可以在异常消息文本中这样做,就像你应该对所有其他不正确的参数一样.
第四,所有其他不正确的参数数据都是IAE,为什么不一致?为什么非法null是如此特殊以至于它应该与所有其他类型的非法争论单独例外?
最后,我接受其他答案给出的论点,即Java API的某些部分以这种方式使用NPE.但是,Java API与从异常类型到命名约定的所有内容都不一致,所以我认为盲目地复制(您最喜欢的部分)Java API并不足以胜过其他考虑因素.
Gre*_*man 295
IllegalArgumentException如果你不想null成为一个允许的值,它似乎是一个被调用的,如果你NullPointerException试图使用一个变量,那么就会被抛出null.
Gar*_*ryF 162
标准是抛出NullPointerException.通常绝对可靠的"有效Java"在第42项(第一版),第60项(第二版)或第72项(第三版)"赞成使用标准例外"中简要讨论了这一点:
"可以说,所有错误的方法调用都归结为非法参数或非法状态,但是其他异常标准地用于某些类型的非法参数和状态.如果调用者在一些禁止空值的参数中传递null,则约定规定抛出NullPointerException而不是IllegalArgumentException."
MB.*_*MB. 136
我一直赞成抛出IllegalArgumentExceptionnull参数,直到今天,当我注意到java.util.Objects.requireNonNullJava 7中的方法时.使用该方法,而不是:
if (param == null) {
throw new IllegalArgumentException("param cannot be null.");
}
Run Code Online (Sandbox Code Playgroud)
你可以做:
Objects.requireNonNull(param);
Run Code Online (Sandbox Code Playgroud)
NullPointerException如果您传递的参数是,它将抛出一个null.
鉴于这种方法在中间是正确的,java.util我认为它的存在是一个非常强烈的迹象,即投掷NullPointerException是"Java做事的方式".
我想我无论如何都决定了.
请注意,关于硬调试的参数是假的,因为您当然可以提供一条消息来NullPointerException说明什么是null以及为什么它不应该为null.就像IllegalArgumentException.
一个额外的优点NullPointerException是,在高性能的关键代码中,您可以省去对null的显式检查(以及NullPointerException带有友好的错误消息),并且只需依赖于NullPointerException当您在null上调用方法时自动获取参数.如果你快速调用一个方法(即快速失败),那么你的效果基本相同,只是对开发人员不友好.大多数情况下,最好明确检查并抛出一条有用的消息来指示哪个参数为null,但如果性能指示不改变方法/构造函数的已发布合约,则可以选择更改它.
Mar*_*ouf 70
我倾向于遵循JDK库的设计,特别是Collections and Concurrency(Joshua Bloch,Doug Lea,这些人知道如何设计可靠的API).无论如何,JDK中的许多API都会主动抛出NullPointerException.
例如,Map.containsKey状态的Javadoc :
@throws NullPointerException如果键为null并且此映射不允许空键(可选).
抛出自己的NPE是完全有效的.惯例是在异常消息中包含参数名称null.
模式如下:
public void someMethod(Object mustNotBeNull) {
if (mustNotBeNull == null) {
throw new NullPointerException("mustNotBeNull must not be null");
}
}
Run Code Online (Sandbox Code Playgroud)
无论你做什么,不要允许设置错误值,并在其他代码尝试使用它时抛出异常.这使得调试成为一场噩梦.你应该始终遵循"快速失败"的原则.
Chr*_*ith 44
投票给杰森科恩的论点,因为它很好地呈现了.让我一步一步地肢解它.;-)
在NPE的JavaDoc明确地说,"空对象的其他非法使用".如果它仅限于运行时遇到null的情况,那么所有这些情况都可以更简洁地定义.
如果你假设错误的话就无法帮助它,但假设封装正确应用,你真的不应该关心或注意null是否被不正确地解除引用而不是方法是否检测到不合适的null并且关闭了异常.
实际上,其他无效参数可能导致各种其他异常.UnknownHostException,FileNotFoundException,各种语法错误异常,IndexOutOfBoundsException,身份验证失败等等.
总的来说,我觉得NPE受到很多诽谤,因为传统上它与代码无法遵循故障快速原则有关.而且,加上JDK未能用消息字符串填充NPE,确实产生了一种强烈的负面情绪,而这种情绪并不是很有根据.实际上,从运行时的角度来看,NPE和IAE之间的区别仅仅是名称.从这个角度来看,使用名称越精确,您给调用者的清晰度就越高.
Jer*_*ett 17
如果它是一种setter方法并且null正在传递给它,我认为抛出一个更有意义IllegalArgumentException.一个NullPointerException似乎更有意义,在你试图实际使用的情况null.
所以,如果你正在使用它,那就是null,NullPointer.如果它被传入并且它是null,IllegalArgument.
Apache Commons Lang有一个NullArgumentException,它执行了许多这里讨论的事情:它扩展了IllegalArgumentException,它的唯一构造函数接受了应该是非null的参数的名称.
虽然我觉得抛出类似NullArgumentException或IllegalArgumentException之类的内容更准确地描述了特殊情况,但我和我的同事们已经选择遵循Bloch关于这个主题的建议.
不能同意所说的话.早早失败,快失败.相当不错的例外口头禅.
关于抛出哪个例外的问题主要是个人品味问题.在我看来,IllegalArgumentException似乎比使用NPE更具体,因为它告诉我问题是我传递给方法的参数而不是在执行方法时可能生成的值.
我的2美分
小智 7
实际上,抛出IllegalArgumentException或NullPointerException的问题在我看来只是对少数人的"圣战",他们对Java中的异常处理有一个简单的理解.一般来说,规则很简单,如下:
将所有类型的参数约束违规映射到IllegalArgumentException的情况至少有三个非常好的理由,第三个可能是如此严重以至于标记练习错误样式:
(1)程序员不能安全地假设参数约束违规的所有情况都会导致IllegalArgumentException,因为如果没有更具体的异常可用,大多数标准类使用此异常而不是废纸篓.尝试将所有参数约束违规情况映射到API中的IllegalArgumentException只会导致程序员使用您的类失败,因为标准库大多遵循违反您的规则的不同规则,并且您的大多数API用户也将使用它们!
(2)映射异常实际上会导致由单一继承引起的不同类型的异常:所有Java异常都是类,因此仅支持单继承.因此,没有办法创建一个真正说NullPointerException和IllegalArgumentException的异常,因为子类只能从一个或另一个继承.因此,在null参数的情况下抛出IllegalArgumentException会使API用户更难以在程序尝试以编程方式纠正问题时区分问题,例如通过将默认值提供给调用重复!
(3)映射实际上会产生bug掩码的危险:为了将参数约束违规映射到IllegalArgumentException,您需要在每个具有任何约束参数的方法中编写外部try-catch.但是,简单地在此catch块中捕获RuntimeException是不可能的,因为将您使用的libery方法抛出的文档RuntimeExceptions映射到IllegalArgumentException,即使它们不是由参数约束违规引起的.因此,您需要非常具体,但即使这样的努力也无法保护您免于意外地将另一个API(即错误)的未记录的运行时异常映射到API的IllegalArgumentException.因此,即使是最谨慎的映射也可能会掩盖其他库制造商的编程错误,因为违反了方法用户的参数约束,这只是一种极端的行为!
另一方面,通过标准实践,规则保持简单,异常原因保持不受掩盖和具体.对于方法调用者,规则也很简单: - 如果由于传递了非法值而遇到任何类型的文档运行时异常,请使用默认值重复调用(对于此特定异常是必需的),或更正代码 - 另一方面,如果您遇到一个未记录的运行时异常,对于给定的一组参数,请向该方法的制造商提交错误报告,以确保其代码或其文档是固定的.
接受的做法是使用IllegalArgumentException(String message)来声明参数无效并尽可能详细地说明......所以说在非异常的情况下发现参数为null,你会做一些事情像这样:
if( variable == null )
throw new IllegalArgumentException("The object 'variable' cannot be null");
Run Code Online (Sandbox Code Playgroud)
您几乎没有理由隐式使用"NullPointerException".当您尝试在空引用(Like toString())上执行代码时,NullPointerException是Java虚拟机抛出的异常.
抛出一个独立于null参数的异常(无论NullPointerException是自定义类型还是自定义类型)使自动化null测试更加可靠.这种自动化测试可以使用反射和一组默认值完成,如Guava的NullPointerTester.例如,NullPointerTester会尝试调用以下方法...
Foo(String string, List<?> list) {
checkArgument(string.length() > 0);
// missing null check for list!
this.string = string;
this.list = list;
}
Run Code Online (Sandbox Code Playgroud)
......有两个参数列表:"", null和null, ImmutableList.of().它会测试这些调用中的每一个都会抛出预期的NullPointerException.对于此实现,传递一个null清单并没有产生NullPointerException.然而,确实会产生一个IllegalArgumentException因为NullPointerTester碰巧使用默认字符串"".如果NullPointerTester只希望NullPointerException为null值,它捕获的错误.如果它期望IllegalArgumentException,它会错过它.
小智 5
在一般情况下,开发者应该永远不会抛出NullPointerException.当代码尝试取消引用值为null的变量时,运行时抛出此异常.因此,如果您的方法想要显式地禁止null,而不是仅仅发生null值引发NullPointerException,则应该抛出IllegalArgumentException.
一些集合假设null使用NullPointerException而不是拒绝了该集合IllegalArgumentException。例如,如果您将一个包含的集合null与一个拒绝的集合进行比较null,则第一个集合将调用containsAll另一个并捕获它的NullPointerException-但不是IllegalArgumentException。(我正在查看的实现AbstractSet.equals。)
你可以合理地认为,以这种方式使用unchecked异常是一个反模式,即含有比较集合null到不能包含集合null是一个可能的错误,真的应该产生一个异常,或将null在所有集合中是一个坏主意。但是,除非您愿意说equals在这种情况下应该抛出异常,否则您会牢记NullPointerException在某些情况下需要这样做,而在其他情况下则不需要。(“ IAE在NPE之前,但在'c'之后...”)
NullPointerException尝试访问具有当前值为 的引用变量的对象时抛出null。
IllegalArgumentException 当方法接收到格式与方法预期不同的参数时抛出。
作为一个主观问题,这应该是关闭的,但它仍然是开放的:
这是我以前工作地点使用的内部政策的一部分,而且效果非常好.这完全来自记忆,所以我不记得确切的措辞.值得注意的是,他们没有使用已检查的异常,但这超出了问题的范围.他们使用的未经检查的例外分为3大类.
NullPointerException:不要故意丢弃.取消引用空引用时,仅由VM抛出NPE.所有可能的努力都是为了确保永远不会抛出这些.@Nullable和@NotNull应与代码分析工具结合使用以查找这些错误.
IllegalArgumentException:当函数的参数不符合公共文档时抛出,这样就可以根据传入的参数来识别和描述错误.OP的情况将属于这一类.
IllegalStateException:在调用函数时抛出,并且它的参数在传递时是意外的,或者与方法所属的对象的状态不兼容.
例如,在具有长度的事物中使用了两个内部版本的IndexOutOfBoundsException.一个IllegalStateException的子类,如果索引大于长度,则使用它.另一个是IllegalArgumentException的子类,如果索引为负数则使用.这是因为您可以向对象添加更多项目,参数将有效,而负数永远无效.
正如我所说,这个系统工作得非常好,并且有人解释为什么存在这样的区别:"根据错误的类型,你可以很容易地弄清楚要做什么.即使你实际上无法想象出了什么问题你可以找出在哪里捕获该错误并创建其他调试信息."
NullPointerException:处理Null案例或放入断言以便不抛出NPE.如果你输入断言只是其他两种类型中的一种.如果可能的话,继续调试,就像首先出现断言一样.
IllegalArgumentException:您的呼叫站点出了问题.如果传入的值来自另一个函数,请找出收到错误值的原因.如果传入的是其中一个参数传播,则错误会检查调用堆栈,直到找到未返回预期的函数.
IllegalStateException:您没有按正确的顺序调用函数.如果您正在使用其中一个参数,请检查它们并抛出描述该问题的IllegalArgumentException.然后,您可以将面颊向上传播到堆栈,直到找到问题为止.
无论如何,他的观点是你只能将IllegalArgumentAssertions复制到堆栈中.您无法将IllegalStateExceptions或NullPointerExceptions传播到堆栈中,因为它们与您的函数有关.
| 归档时间: |
|
| 查看次数: |
154213 次 |
| 最近记录: |