我为属性提供了一个简单的setter方法,并且null不适合此特定属性。 在这种情况下,我总是感到痛苦:我应该抛出IllegalArgumentException还是NullPointerException 从javadocs来看,两者似乎都合适。 有某种可以理解的标准吗? 还是这只是您应该做的任何事情之一,而且两者都是正确的?

===============>>#1 票数:411

由于以下原因,您应该使用IllegalArgumentException (IAE),而不是NullPointerException (NPE):

首先, NPE JavaDoc明确列出了适用NPE的情况。 注意,当不当使用null ,所有这些都将在运行null 相比之下, IAE JavaDoc并不清楚:“抛出该错误以表明方法已传递了非法或不适当的参数。” 是的,就是你!

其次,当您在堆栈跟踪中看到NPE时,您会怎么做? 可能有人取消引用了null 当您看到IAE时,您假定在堆栈顶部的方法的调用者传入了非法值。 再者,后一种假设是正确的,前一种是误导性的。

第三,由于IAE显然是为验证参数而设计的,因此您必须将其视为默认的例外选择,那么为什么要选择NPE? 当然不是因为不同的行为-您真的希望调用代码与IAE分开捕获NPE并因此有所作为吗? 您是否要传达更具体的错误消息? 但是无论如何,您都可以在异常消息文本中执行此操作,就像对所有其他不正确的参数一样。

第四,所有其他不正确的参数数据将是IAE,那么为什么不一致? 为什么非法null如此特殊,以至于它应与所有其他类型的非法论证分开单独的例外?

最后,我接受其他答案给出的论点,即Java API的某些部分以这种方式使用NPE。 但是,Java API与从异常类型到命名约定的所有内容都不一致,因此我认为仅仅盲目复制(您最喜欢的部分)Java API不足以胜过其他考虑。

===============>>#2 票数:293 已采纳

如果您不希望将null用作允许的值,则似乎调用了IllegalArgumentException ,并且如果您尝试使用一个结果为null的变量,则将引发NullPointerException

===============>>#3 票数:162

标准是抛出NullPointerException 通常可靠的“有效Java”在项目42(第一版),项目60(第二版)或项目72(第三版)“优先使用标准异常”中对此进行了简要讨论:

“可以说,所有错误的方法调用都可以归结为非法参数或非法状态,但是对于某些类型的非法参数和状态,通常会使用其他例外。如果调用者在某些参数中传递了null,则禁止使用null值,惯例规定:会抛出NullPointerException而不是IllegalArgumentException。”

===============>>#4 票数:136

直到今天,当我注意到Java 7中的java.util.Objects.requireNonNull方法时,我都赞成为空参数抛出IllegalArgumentException ,而不是这样做:

if (param == null) {
    throw new IllegalArgumentException("param cannot be null.");
}

你可以做:

Objects.requireNonNull(param);

如果您传递的参数为null ,它将抛出NullPointerException

鉴于该方法在java.util中间很合适,我认为它的存在是一个很强的迹象,表明抛出NullPointerException是“ Java的处理方式”。

我想我已经决定了。

请注意,关于硬调试的参数是虚假的,因为您当然可以向NullPointerException提供一条消息,说明什么是null以及为什么它不应该为null。 就像IllegalArgumentException

NullPointerException另一个优点是,在高性能的关键代码中,您可以省去对null的显式检查(以及带有友好错误消息的NullPointerException ),而仅依靠NullPointerException即可在调用方法时自动获得在null参数上。 如果您快速调用一个方法(即快速失败),那么您将获得基本相同的效果,只是对开发人员而言不太友好。 在大多数情况下,最好进行显式检查并抛出有用的消息以指示哪个参数为空,这可能更好,但是,如果性能要求不改变方法/构造函数的已发布约定,那么可以更改它是一个很好的选择。

===============>>#5 票数:70

我倾向于遵循JDK库的设计,尤其是Collections和Concurrency(Joshua Bloch,Doug Lea,那些人知道如何设计可靠的API)。 无论如何,JDK中的许多API都会主动抛出NullPointerException

例如, Map.containsKey的Javadoc指出:

如果键为null,并且此映射不允许空键,则@throws NullPointerException(可选)。

抛出自己的NPE是完全有效的。 约定将在异常消息中包含为空的参数名称。

模式如下:

public void someMethod(Object mustNotBeNull) {  
    if (mustNotBeNull == null) {  
        throw new NullPointerException("mustNotBeNull must not be null");  
    }  
}

无论您做什么,都不要设置一个错误的值,并在以后其他代码尝试使用它时引发异常。 这使得调试成为一场噩梦。 您应该始终遵循“快速失败”的原则。

===============>>#6 票数:44

投票赞成杰森·科恩(Jason Cohen)的论点,因为它的论据很好。 让我逐步解散它。 ;-)

  • NPE JavaDoc明确表示“其他对null对象的非法使用” 如果仅限于运行时在不应该遇到null的情况下,则可以更简洁地定义所有此类情况。

  • 如果您假设做错了事,那将无济于事,但假设正确应用了封装,您真的不应该在意或注意到是否对空值进行了不适当的引用,而不是方法是否检测到不适当的空值并触发了异常。

  • 由于多种原因,我选择NPE而不是IAE

    • 关于非法活动的性质更具体
    • 错误允许空值的逻辑与错误允许非法值的逻辑有很大的不同。 例如,如果我正在验证用户输入的数据,如果我得到的值是不可接受的,则该错误的根源在于应用程序的最终用户。 如果我得到一个空值,那是程序员错误。
    • 无效值可能导致诸如堆栈溢出,内存不足错误,解析异常等问题。实际上,大多数错误通常在某些时候在某些方法调用中作为无效值出现。 因此,我认为IAE实际上是RuntimeException下所有异常的最通用
  • 实际上,其他无效参数可能导致各种其他异常。 UnknownHostExceptionFileNotFoundException ,各种语法错误异常, IndexOutOfBoundsException ,身份验证失败等,等等。

总的来说,我感到NPE的弊端很大,因为传统上将NPE与未能遵循快速失败原则的代码相关联。 那,加上JDK无法用消息字符串填充NPE,确实造成了强烈的负面情绪,这是没有根据的。 实际上,从运行时角度来看,NPE和IAE之间的区别严格来说就是名称。 从这个角度来看,名称越精确,您给呼叫者的清晰度就越高。

===============>>#7 票数:20

这是一个“圣战”风格的问题。 换句话说,这两种选择都是好的,但是人们会有自己的偏好,可以捍卫自己的生命。

===============>>#8 票数:17

如果它是一个setter方法,并且将null传递给它,则我认为抛出IllegalArgumentException更为有意义。 在您尝试实际使用null的情况下, NullPointerException似乎更有意义。

因此,如果您使用它并且它为null ,则为NullPointer 如果正在传递且为null ,则为IllegalArgument

===============>>#9 票数:9

Apache Commons Lang有一个NullArgumentException ,它可以完成此处讨论的许多事情:它扩展了IllegalArgumentException,并且它的唯一构造方法采用了应该为非null的参数名称。

尽管我觉得抛出类似NullArgumentException或IllegalArgumentException之类的东西可以更准确地描述特殊情况,但我和我的同事还是选择遵从Bloch关于该主题的建议。

===============>>#10 票数:7

实际上,在我的拙见中,抛出IllegalArgumentException或NullPointerException的问题只是对Java异常处理了解不足的少数人的“圣战”。 通常,规则很简单,如下所示:

  • 必须尽可能快地表明参数约束违规(->快速失败),以避免出现难以调试的非法状态
  • 如果出于任何原因导致无效的空指针,则抛出NullPointerException
  • 如果数组/集合索引非法,则抛出ArrayIndexOutOfBounds
  • 如果数组/集合大小为负数,则抛出NegativeArraySizeException
  • 如果上面没有涉及非法参数,并且您没有其他更特殊的异常类型,则将IllegalArgumentException当作废纸bas
  • 另一方面,如果由于某些正当原因而无法通过快速失败避免在字段中违反约束,则将其作为IllegalStateException或更具体的检查异常进行捕获并重新抛出。 在这种情况下,切勿传递原始的NullPointerException,ArrayIndexOutOfBounds等!

至少有三个非常好的理由来反对将各种参数约束违规映射到IllegalArgumentException的情况,第三个原因可能是如此严重以至于标记了实践不良样式:

(1)程序员不能安全地假定所有违反参数约束的情况都会导致IllegalArgumentException,因为如果没有更多特定类型的异常可用,则大多数标准类都使用此异常,而不是将其当作废纸ket。 尝试在API中将所有违反参数约束的情况映射到IllegalArgumentException只会导致使用类的程序员感到沮丧,因为标准库通常遵循违反您的规则,并且大多数API用户也会使用它们!

(2)映射异常实际上是由单一继承引起的另一种异常:所有Java异常都是类,因此仅支持单一继承。 因此,由于子类只能从一个或另一个继承,所以无法创建一个真正表示NullPointerException和IllegalArgumentException的异常。 因此,在参数为null的情况下抛出IllegalArgumentException,每当程序尝试以编程方式纠正问题时,例如通过将默认值输入重复调用中,API用户就更难区分问题。

(3)映射实际上会造成错误掩盖的危险:为了将违反参数约束的行为映射到IllegalArgumentException,您将需要在每个具有受限参数的方法中编写外部try-catch。 但是,仅在此catch块中捕获RuntimeException是不可能的,因为这可能会将由您内部使用的libery方法抛出的已记录的RuntimeException映射到IllegalArgumentException,即使它们不是由参数约束冲突引起的。 因此,您需要非常具体,但是即使您不小心将另一个API的未记录的运行时异常(即错误)映射到您的API的IllegalArgumentException中,这种保护也无法为您提供保护。 因此,即使是最仔细的映射也有可能掩盖其他库制造商的编程错误,因为这违反了方法用户的参数约束,这简直就是荒唐的行为!

另一方面,使用标准实践,规则保持简单,异常原因保持隐蔽和具体。 对于方法调用者来说,规则也很容易:-如果由于传递了非法值而遇到记录在案的任何类型的运行时异常,请使用默认值重复调用(此特定异常是必要的),或更正代码-另一方面,如果遇到未针对给定参数集记录的运行时异常,请向方法的制定者提交错误报告,以确保其代码或文档均已修复。

===============>>#11 票数:7

我完全同意所说的话。 早期失败,快速失败。 相当不错的异常口头禅。

有关抛出哪个异常的问题主要取决于个人喜好。 在我看来,IllegalArgumentException似乎比使用NPE更具体,因为它告诉我问题出在我传递给方法的参数上,而不是执行该方法时可能生成的值。

我的2美分

===============>>#12 票数:6

引发null参数专有的异常(无论是NullPointerException还是自定义类型),都使自动null测试更加可靠。 可以像GuavaNullPointerTester一样,通过反射和一组默认值来完成此自动化测试。 例如, NullPointerTester会尝试调用以下方法...

Foo(String string, List<?> list) {
  checkArgument(string.length() > 0);
  // missing null check for list!
  this.string = string;
  this.list = list;
}

...具有两个参数列表: "", nullnull, ImmutableList.of() 它将测试这些调用中的每一个都引发预期的NullPointerException 对于此实现,传递一个null列表不会产生NullPointerException 但是,它确实会产生IllegalArgumentException因为NullPointerTester恰好使用默认字符串"" 如果NullPointerTester仅期望NullPointerException作为null值,则它将捕获该错误。 如果期望IllegalArgumentException ,它将错过它。

===============>>#13 票数:6

如果使用IllegalArgumentException(String message)来声明参数无效并提供尽可能多的详细信息,这是公认的做法。也就是说,在异常非null的情况下,发现参数为null,您可以执行一些操作像这样:

if( variable == null )
    throw new IllegalArgumentException("The object 'variable' cannot be null");

您实际上没有理由隐式使用“ NullPointerException”。 NullPointerException是Java虚拟机在您尝试对空引用执行代码时抛出的异常(如toString() )。

===============>>#14 票数:5

一些集合假定使用NullPointerException而不是IllegalArgumentException拒绝null 例如,如果将包含null的集合与拒绝null的集合进行比较,则第一个集合将在另一个集合上调用containsAll并捕获其NullPointerException ,但不会捕获IllegalArgumentException (我正在研究AbstractSet.equals的实现。)

你可以合理地认为,以这种方式使用unchecked异常是一个反模式,即含有比较集合null到不能包含集合null是一个可能的错误,真的应该产生一个异常,或把null的集合在所有的一个坏主意。 但是,除非您愿意说在这种情况下equals应该抛出异常,否则您要牢记在某些情况下需要NullPointerException ,而在其他情况下则不需要。 (“ IAE在NPE之前,但在'c'之后...”)

===============>>#15 票数:5

作为一个主观的问题,应将其关闭,但仍处于打开状态:

这是我以前的工作场所所使用的内部政策的一部分,并且效果很好。 这些全都来自记忆,所以我不记得确切的用词了。 值得注意的是,他们没有使用检查异常,但这超出了问题的范围。 他们确实使用的未经检查的异常分为3个主要类别。

NullPointerException:不要故意抛出。 当取消引用空引用时,仅由VM抛出NPE。 应尽一切可能确保不会抛出这些错误。 @Nullable和@NotNull应该与代码分析工具结合使用以查找这些错误。

IllegalArgumentException:当函数的参数不符合公共文档时抛出,从而可以根据传入的参数来识别和描述错误。OP的情况将属于此类。

IllegalStateException:调用函数且其参数在传递时意外或与该方法所属的对象的状态不兼容时抛出。

例如,在具有长度的事物中使用了IndexOutOfBoundsException的两个内部版本。 一个IllegalStateException的子类,如果索引大于长度,则使用它。 如果索引为负,则使用IllegalArgumentException的另一个子类。 这是因为您可以向该对象添加更多项目,并且该参数将有效,而负数则永远无效。

就像我说的那样,该系统确实运行良好,需要有人来解释为什么存在这种区别:“根据错误的类型,您很容易确定要做什么。即使您实际上无法弄清楚找出出了什么问题,您可以找出在哪里捕获该错误并创建其他调试信息。”

NullPointerException:处理Null大小写或放入断言中,以便不引发NPE。 如果您声明,则只是其他两种类型之一。 如果可能,请继续进行调试,就像断言首先存在于此一样。

IllegalArgumentException:您的呼叫站点有问题。 如果传入的值来自另一个函数,请找出为什么接收到不正确的值。 如果传递的参数之一是传播,则错误会检查调用堆栈,直到找到未返回期望值的函数。

IllegalStateException:您未按正确的顺序调用函数。 如果您使用的是其中一个参数,请检查它们并抛出一个IllegalArgumentException描述问题。 然后,您可以将脸颊朝着堆栈传播,直到找到问题为止。

无论如何,他的观点是您只能将IllegalArgumentAssertions复制到堆栈中。 您无法在堆栈上传播IllegalStateExceptions或NullPointerExceptions,因为它们与您的功能有关。

===============>>#16 票数:4

二分法...它们是不重叠的吗? 整体中只有不重叠的部分才能进行二分法。 照我看来:

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));

===============>>#17 票数:4

尝试使用当前值为null的引用变量访问对象时引发NullPointerException

当方法接收的参数格式与方法预期的格式不同时,抛出IllegalArgumentException

===============>>#18 票数:4

我想从其他非法参数中选出Null参数,因此我从IAE派生了一个名为NullArgumentException的异常。 甚至不需要读取异常消息,我知道将null参数传递到方法中,并且通过读取消息,我可以找出哪个参数为null。 我仍然使用IAE处理程序捕获NullArgumentException,但是在我的日志中可以快速看到差异。

===============>>#19 票数:4

通常,开发人员永远不要抛出NullPointerException。 当代码尝试取消引用值为空的变量时,运行时将引发此异常。 因此,如果您的方法想要显式禁止null,而不是碰巧使null值引发NullPointerException,则应抛出IllegalArgumentException。

===============>>#20 票数:3

根据您的方案, IllegalArgumentException是最佳选择,因为null对您的属性而言不是有效值。

===============>>#21 票数:0

理想情况下,不应引发运行时异常。 应该为您的方案创建一个已检查的异常(业务异常)。 因为如果抛出并记录了这些异常中的任何一个,则在浏览日志时会误导开发人员。 取而代之的是,业务异常不会造成这种恐慌,通常在对日志进行故障排除时会被忽略。

===============>>#22 票数:-1

指向以上两个异常的链接中的定义为IllegalArgumentException:被抛出以指示方法已传递了非法或不适当的参数。 NullPointerException:当应用程序在需要对象的情况下尝试使用null时抛出。

这里的最大区别是,在检查方法的参数是否有效时应该使用IllegalArgumentException。 当对象为null时,只要“使用”对象,就应该使用NullPointerException。

我希望这有助于将两者放在一起。

===============>>#23 票数:-1

在这种情况下,IllegalArgumentException使用您的API向用户传达明确的信息,即“不应为null”。 正如其他论坛用户指出的那样,只要您愿意使用API​​向用户传达正确的信息,就可以使用NPE。

GaryF和tweakt删除了推荐使用NPE的“有效Java”(我发誓)参考。 并且查看如何构造其他好的API是了解如何构造API的最佳方法。

另一个很好的例子是查看Spring API。 例如,org.springframework.beans.BeanUtils.instantiateClass(构造函数ctor,Object [] args)具有Assert.notNull(ctor,“构造函数不得为null”)行。 org.springframework.util.Assert.notNull(Object object,String message)方法检查传入的参数(对象)是否为null,如果存在,则抛出新的IllegalArgumentException(message),然后将该异常捕获到组织中。 springframework.beans.BeanUtils.instantiateClass(...)方法。

===============>>#24 票数:-1

如果它是“设置者”,或者是我以后要让某个成员使用的某个地方,那么我倾向于使用IllegalArgumentException。

如果现在要在该方法中使用(取消引用),我会主动抛出NullPointerException。 与让运行时执行此操作相比,我更喜欢此操作,因为我可以提供一条有用的消息(似乎运行时也可以执行此操作,但这又是另一天的麻烦)。

如果我要覆盖某个方法,则将使用该覆盖的方法所使用的任何东西。

===============>>#25 票数:-1

您应该抛出一个IllegalArgumentException,因为它会使程序员很明显他做了无效的事情。 开发人员习惯于看到VM抛出的NPE,以至于任何程序员都不会立即意识到自己的错误,而是会开始四处张望,甚至更糟糕地将代码归咎于“笨拙”。

===============>>#26 票数:-5

如果选择抛出NPE,并且在方法中使用参数,则显式检查null可能是多余且昂贵的。 我认为VM已经为您做到了。

  ask by Mike Stone translate from so

未解决问题?本站智能推荐: