以编程方式抛出NullPointerException可以吗?

当有后置条件时,方法的返回值不能为空,可以做些什么?

我可以

assert returnValue != null : "Not acceptable null value"; 

但断言可能被closures!

那么可以这样做

 if(returnValue==null) { throw new NullPointerException("return value is null at method AAA"); } 

或者是这样的情况下使用用户定义的exception(如NullReturnValueException)更好?

我觉得在JVM为你做这件事之前尽可能早地抛出一个NPE是没问题的,特别是对于空参数。 似乎有一些关于这个问题的争论,但在Java SE库中有很多例子完全是这样做的。 我不明白为什么NPE应该在你不能自己抛弃的方面是神圣的。

但是,我离题了。 这个问题是关于不同的东西。 你在谈论一个后置条件,说明返回值不能为空。 在这种情况下肯定是空的意味着你在这个方法里面有一个bug?

你怎么logging这个? “如果返回值意外为空,此方法抛出NullPointerException”? 没有解释这是怎么发生的? 不,我会在这里使用一个断言。 例外应该用于可能发生的错误 – 而不是涵盖如果方法内部有问题可能发生的事情,因为这对任何人都没有帮助。

我会build议你永远不要抛出自己的NullPointerException

正如ThorbjørnRavn Andersen在下面的评论中所说的,不要这么做的主要原因是,你不希望把“真NPE”与故意抛出的NPE混合在一起。

因此,直到您确信自己能够识别“有效”的NPE,当您想告诉API用户null不是有效的参数值时,我build议使用IllegalArgumentException 。 当非法的空parameter passing时,你的方法的行为应该被logging下来。

另一个(更现代的imho)选项是在参数附近使用@NotNull注释。 这是一篇关于使用@NotNull注释的文章 。

正如我前面提到的,也可能有这样的情况,投掷NPE不会让你或你的队友感到困惑:NPE的原因应该清晰可辨。

例如,如果你使用一些带有预处理模块的库,比如Guava ,那么我发现使用类似checkNotNull()的方法是处理非法传播的空值的一个好方法。

checkNotNull(arg, msg)会抛出NPE,但是从堆栈跟踪中可以清楚的看出它是由Preconditions.checkNotNull()产生的,因此它不是一个未知的错误,而是一个预期的行为。

鉴于NullPointerException是在Java中传递意外的空值的惯用方式,我build议您抛出一个标准的NullPointerException而不是一个本地的。 另外请记住,最小惊喜的原则将表明,在系统exceptiontypes存在的情况下,您不会发明自己的exceptiontypes。

断言是很好的debugging,但不好,如果你必须处理某些条件,所以这不是一个很好的方法来处理错误的情况。

NullPointerException的问题在于,当您忘记检查某些内容是否为空或给出错误的参数为null时发生该错误,而不应该这样做。

根据我的经验,Java程序员非常快速地学习到这个exception是由代码中的错误引起的,所以手动抛出这个exception对于大多数人来说是极其混乱的。 IllegalArgumentException是更好的想法,当你传递不可接受的参数(如null,其中的东西一定不能为空)。

它也触发另一个启发式。 NPE =某人在代码中犯了错误, IllegalArgumentException =给予该方法的对象无效。

另一方面,javadoc告诉:

应用程序应该抛出这个类的实例来指示
null对象的其他非法使用。

所以抛NPE是合法的 ,但这不是常见的做法,所以我会推荐IllegalArgumentException

当然,抛出NullPointerException并不是一个普遍的法则,但如果你真的应该在这样一个抽象的例子中,很难回答。 你不想做的就是把人们放在试图捕获NullPointerException的位置上。 这样的代码(真实的例子,我发誓):

 catch (NullPointerException npe) { if (npe.getMessage().equals("Null return value from getProdByCode") { drawToUser("Unable to find a product for the product type code you entered"); } } 

是一个肯定的指标,你做错了什么。 因此,如果空返回值是您实际能够通信的某些系统状态的指示符,请使用传达该状态的exception。 没有太多的情况下,我可以想到,为了查找空指针,检查引用是否合理。 通常情况下,下一行代码会放弃nullpointer(或更多信息)!

我会考虑使用NullPointerException确定, 如果你还记得描述。 这是调查人员的工作(行号可能会改变)。 还要记住在特殊情况下您的方法会抛出空指针exception。

如果你在一开始就检查你的方法参数,那么throw new IllegalArgumentException("foo==null")一个throw new IllegalArgumentException("foo==null")也是可以接受的。

JavaDoc for NullPointerException指出:

在应用程序试图在需要对象的情况下使用null时抛出。 这些包括:

 * Calling the instance method of a null object. * Accessing or modifying the field of a null object. * Taking the length of null as if it were an array. * Accessing or modifying the slots of null as if it were an array. * Throwing null as if it were a Throwable value. 

应用程序应抛出此类的实例来指示其他非法使用null对象。

我认为违反后条件是非法行为。 不过,我认为你使用的exception并不重要,因为我们正在讨论的应该是(而且希望是)无法访问的代码path,因此你不会有特定于该exception的error handling,因此唯一的影响这个名字是在一个没有人可能看到的日志文件中的一些条目的不同措辞。

如果相反,您认为后期条件可能被违反,那么包含更多的debugging信息(如调用该方法的参数)可能是一个好主意。

如果你描述了一个返回值不能为null的方法合约,那么你最好确保你不返回null 。 但是这根本不是NullPointerException。 如果你必须返回的值为null那么显然调用者要么给出了错误的参数( IllegalArgumentException ),还没有处于有效状态( IllegalStateException ),或者发生了除NullPointerException之外的其他更有意义的exception情况表示编程错误)。

http://pmd.sourceforge.net/pmd-5.0.1/rules/java/strictexception.html
“避免抛出NullPointerExceptionexception,这是令人困惑的,因为大多数人会认为虚拟机抛出它,考虑使用IllegalArgumentException,这将被清楚地看作是程序员发起的exception。

专家编写的O'Reilly的Java中的一本书中列出了一个名为NullPointerException的定义:

指示尝试访问字段或调用空对象的方法。

由于返回null不是这些事情之一,我认为这将是更合适的编写自己的exception。

在逻辑非常深入之前抛出NPE通常是一个非常好的主意,因此调用程序员将很难找出什么是空的。 addListener()方法就是一个很好的例子。

尽pipe如此,JDK还是有许多方法可以做到这一点。

国际海事组织你绝不应该手动抛出一个NullPointerException。 调用例程不会知道真正的或手动的NullPointerException而不检查描述。 在这种情况下,它看起来像你想滚动你自己的exception匹配的问题更接近,以便调用方法可以正确地恢复frm这个exception。 也许PostConditionException在许多情况下都是通用的。

在Java-verse中,当期望一个对象时,null总是一个有效的值。 你最好避免这种不可能的后期条件。 如果你真的不能遵守null,那么你将不得不重做你的方法,这样你才能返回一个原语。

正如约书亚·布洛克曾经说过的:“空无用!” :)每当有空是我的脸,我尝试使用可选的番石榴提供。 我的优点是很多的。

绝对没错。

即使JDK7解决这个问题。 请参阅对象#requireNonNull

 void doWith(final Object mustBeNotNull) { /* // bush style if (mustBeNotNull == null) { throw new IllegalArgumentException("mustBeNotNull must not be null"); } */ /* // obama style if (mustBeNotNull == null) { throw new NullPointerException("mustBeNotNull must not be null"); } */ // kangnam style Objects.requireNonNull(mustBeNotNull, "mustBeNotNull must not be null"); assert mustBeNotNull != null; } 

当有后置条件时,方法的返回值不能为空,可以做些什么?

后置条件意味着如果条件不满足,则所讨论的方法有一个错误。 在代码中expression这一点的方法是在后置条件中使用assert 。 直接抛出exception,如NullPointerExceptionIllegalStateException ,会有点误导,因此被误导。

以编程方式抛出NullPointerException可以吗?

NPE的Java API文档是肯定的,但是根据本页上的投票来看,3:1的大部分开发人员说不。 所以我会说这取决于你的工作组的惯例。

API文档首先列出JVM引发NPE的情况,因为代码试图在需要某种types的对象(如调用方法或访问字段)的空引用上调用操作,而null不是对象。 然后说:

应用程序应抛出此类的实例来指示其他非法使用null对象。

有趣的是, null在这里被称为“对象”,事实并非如此。 这让我想起了NullPointerException的名字对于一个没有指针的语言来说是很奇怪的。 (这应该是Microsoft .NET类库中的NullReferenceException 。)

那么我们应该closures这个数字的API文档? 我不这么认为。 类库使用文档中描述的NPE,例如在java.nio.channels

除非另有说明,否则将nullparameter passing给此包中的任何类或接口中的构造函数或方法将导致抛出NullPointerException

这不是由JVM生成的NPE,而是一个带有附加错误消息的编码NPE,指出哪个参数为null (如"in" is null! )。 (可以通过执行javap -c -p java.nio.channels.Channels | more ,查找private static void checkNotNull 。)有很多类以这种方式使用NPE,本质上是IllegalArgumentException一个特例。

所以在仔细研究之后,我发现这是对NPE的一个很好的使用,因此我同意API文档和less数Java开发人员(根据本页上的投票),你们都是有权利在你自己的代码中使用NPE,就像Java类库一样,也就是通过提供一个错误信息,这在JVM生成的NPE中是显而易见的,这就是为什么说两种NPE没有问题分开。

为了解决这个问题,NPE将被抛在后面:尽早发现错误,而不是允许JVM继续执行程序,可能涉及到磁盘或networkingI / O(以及延迟),并生成不必要的大堆栈跟踪。

是的,这是可以的,但是我认为让这种事情发生是一个更好的决定。

Java程序员和null的问题在于人们来自C / C ++背景,其中NULL意味着很多不同。 在C / C ++取消引用NULL(或野生)指针是一个严重的问题,可能会导致奇怪的内存问题或崩溃你的程序(显然不希望)。 如果你能摆脱C / C ++的思考方式,并且意识到你有这个额外的层,那么JVM就会为你处理这个条件,所以你会开始考虑NULL。

在C ++中,我们有引用,例如,永远不能分配NULL。 在Java中,没有引用,但Java对象参数的行为更像C ++指针。 但是在Java中有很多情况下,一个方法隐式地不应该接收一个参数的空值! 那么我们该怎么办?

像在C ++中一样对Java进行null处理的问题是,这会导致无处不在的空检查,而在C ++中,您只需声明一个引用的方法,该方法明确指出它不接受NULL。 很快,每一种方法都必须有一个理智的检查,只是为了在那个时候断言程序的状态,造成一团糟。

假设一个方法的默认合约是null对于一个参数值是无效的,这是一个更好的工作状态。

为什么? 那么,让我们看看当这样一个方法接收null作为参数值时会发生什么。 a)也许这是可以的,因为它并没有将价值作为行为的一部分。 在这种情况下,没有任何反应。 b)价值被取消。 在这种情况下,来自JVM的行为正是我们所希望的:抛出一个exception,表示由于参数值为null而违反了方法的契约,并且它包含一个堆栈跟踪,将我们带到在用这种方法来利用价值的方法中。

人们对NPE有疑问,因为他们认为当你看到日志中的NPE时,就意味着“有人搞砸了”。 但是让我们考虑一下。 事实上,NPE作为一个指标而不是预期的行为,其差异是什么? 我认为使用NPE作为预期行为的主要区别(和优点)在于,它不是指它发生的方法,而是指向调用者违反方法合同的方法。 这是更有用的信息。 如果我们只是简单地检查null并抛出一个不同的exception,那么当调用者违反方法的契约时,我们可能会错误地认为观察到的行为是一个预期的错误。 恭喜你,你正确地预料到你的调用者在调用方法时可能会搞砸了 – 但是你所做的一切都会让你误以为exception的真正原因是什么 – 或者最多你使用两个不同的exception类同时指出同样的事情,并大量地将代码与不必要的垃圾混淆在一起。

所以,当人们认为NPE是禁忌的时候, 从字面上来说,人们不会允许它被抛出,因为它会带来某种羞耻的感觉 – 就好像你不够聪明,因为你没有猜测到某个值是空的。 那么,我得到了你们的消息,你只是写更多无用的代码来做同样的事情。

一些例子:

 public void foo(Object o) { if (o == null) { throw new IGotchaException("HA! You're an IDIOT! I knew it!!"); } o.bar(); } public void foo(Object o) { o.bar(); } 

^在政治上不同。 function上,不是那么多。

 public void foo(int a, long b, double c, Object o) { if (o == null) { throw new IllegalArgumentException("Oh. Uh. Well, you've passed me null here. I... I'm not sure where to go from here because this object is kind of required for this function to do what it's supposed to do. Soooo... wouldja mind reworking your code a little bit so as to not pass null to this function as a parameter?! That'd be great thanks. Oh by the way, it's cause we deference o 40 lines below here"); } // ... o.doSomethingWithA(a); } public void foo(int a, long b, double c, Object o) { // ... o.doSomethingWithA(a); // NullPointerException, line 40, eg it wasn't OK to pass null for o you lunkhead } 

^也许会节省几个CPU周期,代价是很多烦人的代码。 但是,在第二种情况下我们做的比较less。

 public void foo(Object a, Object b, Object c, Object d) { if (a == null) throw IllegalArgumentException("jackass"); if (b == null) throw IllegalArgumentException("jackass"); if (c == null) throw IllegalArgumentException("jackass"); // But d is totally OK! // ... c.setSomeValueThatMayBeNull(d); } public void foo(Object a, Object b, Object c, Object d) { // ... c.setSomeValueThatMayBeNull(d); // Throws null pointer exception if c is null, but not if d is null. Which is basically the same as above } 

合同隐含在声明中,而不是方法开始时的exception情况。 没有其他缺点。

 public void foo(Object o) { if (o == null) { doTheBoogie(); } else { doTheRobot(); } } 

^不好

 public void foo(Object o, int b) { Bar value = o.findSomethingWhichMayExist(b); if (value == null) return; value.doSomething(); } 

^使用空返回值来表示没有值。 好。

人们遇到NPE问题的另一个原因是他们不知道如何处理exception。 NPE永远不应该是一个显示器。 适当的行为是捕获RuntimeException,大概是在调用堆栈中更高(或更低,取决于您如何看待它)的级别,将其捕获并在“main”之前报告。 也就是说,假设你正在开发那种需要更有弹性的程序,并且不能在发生 NPE时崩溃

底线:永远不要期望传递方法参数的空值是一个有效的事情。 绝对不要为显式接受null的方法创build一个合约,并将其视为有效的值。 但是, 允许空指针exception发生,并且让代码失败,或者当不重要的时候不会失败。

我同意以前的答案中的说法,NPE是代码中的错误,不应该抛出,但开发人员应该修复意外的空。 但是这个状态大部分时间都可以通过testing来防止。

这个问题在7年之前问过,但是现在我们在java 8中有了Optional,这个特性可以防止NPE。

最后一个解决scheme,我认为你应该检查null对象,如果它是平等的,所以抛出你自己的exception与发生的事情的描述。

抛出这个exception在某些情况下不是一个好习惯,我想知道为什么当你已经用if语句来捕捉它时?

如果(的returnValue == NULL)