I would recommend you never throw NullPointerException by yourself.
The main reason not to do this, as Thorbjørn Ravn Andersen says in a comment below, is that you don't wan't to mix 'real, bad NPEs' with NPEs thrown intentionally.
So, until you're confident that you're able to recognize 'valid' NPE, I'd recommend to use IllegalArgumentException when you want to tell to your API user that null is not a valid argument value. Your method's behavior when illegal null-parameter passed should be documented.
As I mentioned earlier, there can also be cases, when throwing NPE will not be confusing either to you or to your teammates: NPE cause should be clear and recognizable.
For instance, if you use some library with preconditions module, like Guava, then I find using checkNotNull()-like methods is a preferable way to deal with illegally-passed nulls.
checkNotNull(arg, msg) throws NPE, but from the stacktrace it's quite clear, that it was produced by Preconditions.checkNotNull() and thus it's not an unknown bug but rather expected behavior.
I see no problem with throwing a NPE as early as possible before the JVM does it for you - in particular for null arguments. There seems to be some debate about this, but there are many examples in the Java SE libraries that does exactly this. I cannot see why NPE should be holy in the aspect that you are not able to throw it yourself.
However, I digress. This question is about something different. You are talking about a post-condition stating that the return value mustn't be null. Surely null in this case would mean you have a bug inside the very method?
How would you even document this? "This method throws a NullPointerException if the return value unexpectedly is null"? Without explaining how this could happen? No, I would use an assertion here. Exceptions should be used for errors that can conceivably happen - not to cover things that can happen if there's something wrong inside the method, because that does not help anybody.
Given that NullPointerException is the idiomatic way to communicate an unexpected null value in Java, I would recommend you throw a standard NullPointerException and not a homegrown one. Also keep in mind that the principle of least surprise would suggest that you don't invent your own exception type for a case where a system exception type exists.
Assertions are good for debugging but not good if you have to handle certain conditions so that's not really a good way to handle the error condition.
The problem with NullPointerException is, that it occures when you forget to check if something is null or give the wrong argument that is null, and shouldn't.
From my experience, Java programmers learn very quickly that this exception is caused by the bug in code, so throwing it manually will be extremally confusing for most of them. IllegalArgumentException is better idea when you pass unacceptable argument (such as null, where something must not be null).
It triggers also another heuristic. NPE = someone made error in code here, IllegalArgumentException = the object given to the method is invalid.
On the other hand, the javadoc tells:
Applications should throw instances of this class to indicate other illegal uses of the null object.
So throwing NPE would be legal, however it's not the common practice, so I would recommend IllegalArgumentException.
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");
}
}
There certainly isn't a universal law against throwing NullPointerException, but it's tough to answer if you actually should in such an abstracted example. What you don't want to do is put people up the chain in the position of trying to catch NullPointerException. Code like this (real example, I swear):
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");
}
}
Is a surefire indicator you're doing something wrong. So if the null return value is an indicator of some system state that you're actually able to communicate, use an exception that communicates that state. There aren't many cases I can think of where it makes sense to null check a reference just to chuck a nullpointer. Usually the very next line of code would have chucked the nullpointer (or something more informative) anyway!
http://pmd.sourceforge.net/pmd-5.0.1/rules/java/strictexception.html "Avoid throwing NullPointerExceptions. These are confusing because most people will assume that the virtual machine threw it. Consider using an IllegalArgumentException instead; this will be clearly seen as a programmer-initiated exception."
如果您从一开始就检查方法参数,抛出 new IllegalArgumentException("foo==null") 对我来说也是可以接受的。
I would consider that usage of NullPointerException ok, if you remember the description. That is what the person investigating has work with (line numbers may shift). Also remember to document that your methods throw null pointer exceptions in special cases.
If you check your method parameters right in the beginning, a throw new IllegalArgumentException("foo==null") is acceptable to me too.
If you describe a method contract where the return value can not be null, then you had better make sure you don't return null. But this isn't a NullPointerException at all. If the value you have to return is null then clearly the caller has either given you bad arguments (IllegalArgumentException), you are not in a valid state (IllegalStateException), or some other much more meaningful exceptional condition has occurred other than NullPointerException (which usually indicates a programming error).
Thrown when an application attempts to use null in a case where an object is required. These include:
* 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.
Applications should throw instances of this class to indicate other illegal uses of the null object.
I consider violating the post-condition an illegal action. However, I think what exception you use doesn't matter much, because we are talking about a code path that should be (and hopefully is) unreachable, and hence you will not have error handling specific to that exception, and hence the only effect of that name is a different wording of some entry in a log file nobody is ever likely to see.
If in contrast you think the post condition is likely to be violated it might be a good idea to include more debugging information, such as the arguments the method was invoked with.
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;
}
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;
}
IMO you should never manually throw a NullPointerException. The calling routine wouldn't know if the real or manual NullPointerException without checking the description. In this case it looks like you would want to roll your own exception that matches the problem closer, so that the calling method can correctly recover frm this exception. Maybe a PostConditionException would be generic enough for many circumstances.
例如,在 C++ 中,我们有引用,永远不能将其分配为 NULL。在 Java 中,没有引用,但 Java 对象参数的行为更像 C++ 指针。但在 Java 中,有很多情况下,方法不应该隐式接收空值参数!那么,我们该怎么办?
在 Java 中像在 C++ 中那样处理 null 的问题是,这会导致 到处 进行 null 检查,而在 C++ 中,您只需声明一个获取引用的方法,该方法明确指出它不接受 NULL。很快,每个方法都必须进行健全性检查,只是为了断言程序当时的状况,从而造成混乱。
假设方法的默认约定是 null 对参数值无效,这是一种更好的心态。
为什么?好吧,让我们看看当这样的方法接收 null 作为参数值时会发生什么。 a) 也许没问题,因为它不会将值取消引用作为其行为的一部分。在这种情况下,什么也不会发生。 b) 该值被解除引用。在这种情况下,JVM 的行为正是我们想要的:抛出一个异常,表明由于参数值为空而违反了方法的约定,并且它包含一个堆栈跟踪,将我们一路带到以这种方式使用该值的方法中的行。
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();
}
^ 政治上不同。从功能上来说,没有那么多。
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, e.g. it wasn't OK to pass null for o you lunkhead
}
^ 也许可以节省一些 CPU 周期,但代价是大量烦人的代码。然而,我们对第二种情况进行的比较较少。
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
}
^ 契约是从语句中隐含的,而不是方法开头的异常情况。没有其他缺点。
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();
}
Yes, it is OK, but I would argue it's a better decision to just let it happen.
The problem with Java programmers and null is that people come from a C/C++ background, where NULL means something a lot different. In C/C++ dereferencing a NULL (or wild) pointer is a serious issue that can cause strange memory issues or crash your program (obvious not desirable). If you can get out of the C/C++ way of thinking and you realize that you have this extra layer, the JVM, which handles this condition for you, you start to think about NULL a little differently.
In C++ we have references, for instance, which can never be assigned NULL. In Java, there are no references, but Java object parameters behave more like C++ pointers. But there are a lot of situations in Java in which a method implicitly should NOT receive a null value for a parameter! So, what do we do?
The problem with treating null in Java like you do in C++ is that this results in null checks EVERYWHERE, whereas in C++ you would simply be declaring a method to take a reference, which explicitly states that it does not accept NULL. Pretty soon every method has to have a sanity check in it just to assert the condition of the program at that point, creating a mess.
It's a much better state of mind to work under the assumption that a method's default contract is that null is invalid for a parameter value.
Why? Well, let's look at what happens when such a method receives null as a parameter value. a) Perhaps it's OK because it does not dereference the value as part of its behavior. In this case, nothing happens. b) The value is dereferenced. In this case, the behavior from the JVM is exactly what we desire: an exception is thrown indicating that the contract of the method has been violated due to a parameter value being null, and it includes a stack trace bringing us all the way to the line in the method where the value is utilized in this way.
People take issue with NPE because they think that when you see NPE in the logs, it means "someone fucked up". But let's think about this for a second. What is actually the difference in NPE as an indicator of fuckup as opposed to expected behavior? I'd argue the major difference (and advantage) of using NPE as expected behavior is that it points not to the method in which it occurred, but to the caller for violating the method's contract. This is much more useful information. If we were to simply check null and throw a different exception, we might be under the false impression that the observed behavior is an expected error, when really the caller is violating the contract of the method. Congratulations, you correctly anticipated how you the caller might screw up in calling the method - however all you've done is led yourself astray as to what the real cause of the exception is - or at best, you're using two different exception classes to indicate the same thing and massively dirtying up the code with unnecessary garbage in the meantime.
So when it comes down to it people consider NPE to be taboo. Literally people will not allow it to be thrown because there's some sense of shame that goes with it - as if you aren't smart enough because you failed to guess where a value would be null. Well, I got news for you guys, you're just writing more useless code to do the same thing.
Some examples:
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();
}
^ Politically different. Functionally, not so much.
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, e.g. it wasn't OK to pass null for o you lunkhead
}
^ Maybe saves a few CPU cycles at the expense of a lot of annoying code. However, we do less comparisons in the second case.
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
}
^ The contract is implicit from the statement, rather than an exception case at the beginning of the method. Offers no other disadvantage.
public void foo(Object o) {
if (o == null) {
doTheBoogie();
} else {
doTheRobot();
}
}
^ Bad
public void foo(Object o, int b) {
Bar value = o.findSomethingWhichMayExist(b);
if (value == null)
return;
value.doSomething();
}
^ Using null return value to indicate the absence of a value. OK.
Another reason people have problems with NPE is because they don't know how to handle exceptions. NPE should never be a showstopper. The appropriate behavior is to catch RuntimeException, presumably at a much higher (or lower, depending how you see it) level in the call stack that traps it and reports it before "main". That is, assuming you're developing the sort of program that needs to be more resilient and can't just crash when an NPE happens.
Bottom line: don't ever expect it's a valid thing to be passing in null values for method parameters. And definitely don't create a contract for a method that explicitly accepts null and treats it as a valid value. But, allow null pointer exceptions to happen, and let the code fail, or not fail when it doesn't matter, naturally.
It's often a really good idea to throw NPE before the logic gets so deep that the calling programmer will have a hard time figuring out what was null. addListener() methods are a good example.
Uninformed downvotes notwithstanding, there are many methods in the JDK that do exactly this.
In the Java-verse null is always a valid value when expecting an object. You're better off avoiding such impossible post conditions. If you really can't abide a null then you'll have to rework your method so you can return a primitive.
As Joshua Bloch once said : "Null sucks!" :) whenever there is null is my face, I try to use the Optional that guava provides. The advantages are numerous to me.
When there is a post-condition, that return value of a method must not be null, what can be done ?
A post-condition means that the method in question has a bug if the condition is not met. The way to express this in code is by using an assert on the post-condition. Directly throwing an exception, such as a NullPointerException or an IllegalStateException, would be a little misguiding, and hence misguided.
Is it okay to throw NullPointerException programatically?
The Java API doc for the NPE says yes, but, judging by the votes given on this page, a 3:1 majority of developers says no. So I'd say it depends on the conventions in your workgroup.
The API doc first lists the cases where the JVM raises an NPE because code tries to invoke an operation on a null reference that requires an object of some sort (like calling a method or accessing a field), and null is not an object. It then states:
Applications should throw instances of this class to indicate other illegal uses of the null object.
Interestingly, null is called an »object« here, which it is not. Which reminds me that the very name NullPointerException is bizarre for a language that doesn't have pointers. (That should probably have been NullReferenceException as in the Microsoft .NET class library.)
So should we dismiss the API doc on this count? I don't think so. The class library does use the NPE as described in the docs, for example in java.nio.channels:
Unless otherwise noted, passing a null argument to a constructor or method in any class or interface in this package will cause a NullPointerException to be thrown.
This is not an NPE generated by the JVM, but a coded NPE with an attached error message stating which argument was null (like "in" is null!). (The code can be seen by doing javap -c -p java.nio.channels.Channels | more, looking for private static void checkNotNull.) And there are many classes that use NPEs in this fashion, essentially as a special case of IllegalArgumentException.
So after investigating this a bit and thinking about it, I find this to be a good use of the NPE, and hence I agree with the API doc and the minority of Java developers (as per the votes on this page) that you are both entitled and right to use the NPE in your own code in the same way the Java class library does, that is by providing an error message, which is conspicuously missing from JVM generated NPEs, which is why there's no problem telling the two kinds of NPE apart.
To address the minor point that the NPE will be thrown anyway further down the road: It can very well make sense to catch errors early instead of allowing the JVM to go on with the program, possibly involving disk or network I/O (and delays), and generating an unnecessarily large stack trace.
I agree with claim in the previous answers, that the NPE is bug in code and should not be thrown, but developer should fix unexpected null. However this state can be prevented most of time by tests.
The question was asked before 7 years, but now we have Optional in java 8 and this feature allow to prevent NPE.
The last one solution, which have on my mind is that you should check object on null and if it is equal, so throw your own exception with description of what happened.
发布评论
评论(19)
我建议您永远不要自己抛出 NullPointerException 。
正如 Thorbjørn Ravn Andersen 在下面的评论中所说,不这样做的主要原因是你不想将“真正的、糟糕的 NPE”与故意抛出的 NPE 混合在一起。
因此,在您确信能够识别“有效”NPE 之前,我建议您在想要告知 API 用户
null
IllegalArgumentException > 不是有效的参数值。应该记录您的方法在传递非法空参数时的行为。另一个(更现代的恕我直言)选项是在参数附近使用
@NotNull
注释。这是一篇关于使用 @NotNull 注释的文章。
正如我之前提到的,在某些情况下,抛出 NPE 不会让您或您的队友感到困惑:NPE 原因应该清晰且可识别。
例如,如果您使用一些带有前提条件模块的库,例如 Guava,那么我发现使用类似 checkNotNull() 的方法是处理非法传递的空值的更好方法。
checkNotNull(arg, msg)
抛出 NPE,但从堆栈跟踪中可以清楚地看出,它是由Preconditions.checkNotNull()
生成的,因此它不是一个未知的错误,而是预期的行为。I would recommend you never throw
NullPointerException
by yourself.The main reason not to do this, as Thorbjørn Ravn Andersen says in a comment below, is that you don't wan't to mix 'real, bad NPEs' with NPEs thrown intentionally.
So, until you're confident that you're able to recognize 'valid' NPE, I'd recommend to use
IllegalArgumentException
when you want to tell to your API user thatnull
is not a valid argument value. Your method's behavior when illegal null-parameter passed should be documented.Another (more modern imho) option is to use
@NotNull
annotation near the argument.Here is an article about using @NotNull annotation.
As I mentioned earlier, there can also be cases, when throwing NPE will not be confusing either to you or to your teammates: NPE cause should be clear and recognizable.
For instance, if you use some library with preconditions module, like
Guava
, then I find usingcheckNotNull()
-like methods is a preferable way to deal with illegally-passed nulls.checkNotNull(arg, msg)
throws NPE, but from the stacktrace it's quite clear, that it was produced byPreconditions.checkNotNull()
and thus it's not an unknown bug but rather expected behavior.我认为在 JVM 为您执行之前尽早抛出 NPE 没有问题 - 特别是对于空参数。对此似乎存在一些争议,但 Java SE 库中有许多示例正是这样做的。我不明白为什么 NPE 应该是神圣的,因为你不能自己扔它。
然而,我离题了。这个问题是关于不同的事情。您正在谈论一个后置条件,声明返回值不能为空。在这种情况下, null 肯定意味着您的方法内有错误?
您将如何记录这一点? “如果返回值意外为 null,则此方法将引发 NullPointerException”?没有解释这是怎么发生的?不,我会在这里使用断言。异常应该用于可能发生的错误 - 不要涵盖方法内部出现问题时可能发生的事情,因为这对任何人都没有帮助。
I see no problem with throwing a NPE as early as possible before the JVM does it for you - in particular for null arguments. There seems to be some debate about this, but there are many examples in the Java SE libraries that does exactly this. I cannot see why NPE should be holy in the aspect that you are not able to throw it yourself.
However, I digress. This question is about something different. You are talking about a post-condition stating that the return value mustn't be null. Surely null in this case would mean you have a bug inside the very method?
How would you even document this? "This method throws a NullPointerException if the return value unexpectedly is null"? Without explaining how this could happen? No, I would use an assertion here. Exceptions should be used for errors that can conceivably happen - not to cover things that can happen if there's something wrong inside the method, because that does not help anybody.
鉴于 NullPointerException 是 Java 中传递意外空值的惯用方式,我建议您抛出标准的 NullPointerException 而不是自行开发的异常。另请记住,最小意外原则建议您不要在存在系统异常类型的情况下发明自己的异常类型。
断言对于调试很有用,但如果您必须处理某些条件,则断言就不好了,因此这并不是处理错误情况的好方法。
Given that
NullPointerException
is the idiomatic way to communicate an unexpected null value in Java, I would recommend you throw a standardNullPointerException
and not a homegrown one. Also keep in mind that the principle of least surprise would suggest that you don't invent your own exception type for a case where a system exception type exists.Assertions are good for debugging but not good if you have to handle certain conditions so that's not really a good way to handle the error condition.
NullPointerException
的问题是,当您忘记检查某些内容是否为 null 或给出错误的参数(不应该为 null)时,就会发生这种情况。根据我的经验,Java 程序员很快就会知道这个异常是由代码中的错误引起的,因此手动抛出它对于他们中的大多数人来说将是极其混乱的。当您传递不可接受的参数(例如 null,其中某些内容不能为 null)时,
IllegalArgumentException
是更好的主意。它还触发了另一种启发。 NPE = 有人在代码中犯了错误,
IllegalArgumentException
= 赋予该方法的对象无效。另一方面,javadoc 告诉:
因此抛出 NPE 是合法,但这不是常见的做法,所以我建议
IllegalArgumentException
。The problem with
NullPointerException
is, that it occures when you forget to check if something is null or give the wrong argument that is null, and shouldn't.From my experience, Java programmers learn very quickly that this exception is caused by the bug in code, so throwing it manually will be extremally confusing for most of them.
IllegalArgumentException
is better idea when you pass unacceptable argument (such as null, where something must not be null).It triggers also another heuristic. NPE = someone made error in code here,
IllegalArgumentException
= the object given to the method is invalid.On the other hand, the javadoc tells:
So throwing NPE would be legal, however it's not the common practice, so I would recommend
IllegalArgumentException
.当然没有反对抛出 NullPointerException 的普遍法则,但很难回答在这样一个抽象的例子中是否真的应该抛出 NullPointerException。您不想做的就是让人们处于尝试捕获 NullPointerException 的位置。像这样的代码(真实的例子,我发誓):
是一个肯定的指示,你做错了什么。因此,如果 null 返回值是您实际上能够通信的某些系统状态的指示符,请使用通信该状态的异常。我能想到的情况并不多,为了丢弃空指针而对引用进行空检查是有意义的。通常,下一行代码无论如何都会丢弃空指针(或更多信息)!
There certainly isn't a universal law against throwing NullPointerException, but it's tough to answer if you actually should in such an abstracted example. What you don't want to do is put people up the chain in the position of trying to catch NullPointerException. Code like this (real example, I swear):
Is a surefire indicator you're doing something wrong. So if the null return value is an indicator of some system state that you're actually able to communicate, use an exception that communicates that state. There aren't many cases I can think of where it makes sense to null check a reference just to chuck a nullpointer. Usually the very next line of code would have chucked the nullpointer (or something more informative) anyway!
http://pmd.sourceforge.net/pmd-5.0.1 /rules/java/strictException.html
“避免抛出 NullPointerException。这些会令人困惑,因为大多数人会认为是虚拟机抛出的。请考虑使用 IllegalArgumentException;这将明显被视为程序员发起的异常。”
http://pmd.sourceforge.net/pmd-5.0.1/rules/java/strictexception.html
"Avoid throwing NullPointerExceptions. These are confusing because most people will assume that the virtual machine threw it. Consider using an IllegalArgumentException instead; this will be clearly seen as a programmer-initiated exception."
我认为 NullPointerException 的用法是可以的,如果你还记得这个描述。这就是调查人员所从事的工作(行号可能会发生变化)。还要记住记录您的方法在特殊情况下抛出空指针异常。
如果您从一开始就检查方法参数,
抛出 new IllegalArgumentException("foo==null")
对我来说也是可以接受的。I would consider that usage of NullPointerException ok, if you remember the description. That is what the person investigating has work with (line numbers may shift). Also remember to document that your methods throw null pointer exceptions in special cases.
If you check your method parameters right in the beginning, a
throw new IllegalArgumentException("foo==null")
is acceptable to me too.如果您描述的方法约定的返回值不能为
null
,那么您最好确保不返回null
。但这根本不是 NullPointerException。如果您必须返回的值是null
,那么显然调用者要么给了您错误的参数(IllegalArgumentException),您未处于有效状态 (IllegalStateException),或发生了除 NullPointerException(通常表示编程错误)之外的其他更有意义的异常情况。If you describe a method contract where the return value can not be
null
, then you had better make sure you don't returnnull
. But this isn't a NullPointerException at all. If the value you have to return isnull
then clearly the caller has either given you bad arguments (IllegalArgumentException), you are not in a valid state (IllegalStateException), or some other much more meaningful exceptional condition has occurred other than NullPointerException (which usually indicates a programming error).我所著的《O'Reilly's Java in A Nutshell》一书由一位专家编写,其中列出了 NullPointerException 的定义:
由于返回 null 不是这些事情中的任何一个,因此我认为编写自己的异常会更合适。
A book I have called O'Reilly's Java in A Nutshell which is written by an expert lists this definition for NullPointerException:
Since returning null isn't either of those things, I think it'd be more appropriate to write your own exception.
NullPointerException 的 JavaDoc 指出:
我认为违反后置条件是非法行为。但是,我认为您使用什么异常并不重要,因为我们正在讨论应该(并且希望是)无法访问的代码路径,因此您不会有特定于该异常的错误处理,因此唯一的效果该名称是日志文件中某些条目的不同措辞,没有人可能会看到。
相反,如果您认为后置条件可能会被违反,那么包含更多调试信息可能是一个好主意,例如调用方法所使用的参数。
The JavaDoc for NullPointerException states:
I consider violating the post-condition an illegal action. However, I think what exception you use doesn't matter much, because we are talking about a code path that should be (and hopefully is) unreachable, and hence you will not have error handling specific to that exception, and hence the only effect of that name is a different wording of some entry in a log file nobody is ever likely to see.
If in contrast you think the post condition is likely to be violated it might be a good idea to include more debugging information, such as the arguments the method was invoked with.
绝对是的。
甚至 JDK7 也解决了这个问题。请参阅Objects#requireNonNull
Absolutely YES.
Even JDK7 resolve this. See Objects#requireNonNull
IMO 你永远不应该手动抛出 NullPointerException。如果不检查描述,调用例程将不知道是真实的还是手动的 NullPointerException。在这种情况下,您似乎希望滚动自己的异常来更接近地匹配问题,以便调用方法可以正确地从该异常中恢复。也许 PostConditionException 对于许多情况来说足够通用。
IMO you should never manually throw a NullPointerException. The calling routine wouldn't know if the real or manual NullPointerException without checking the description. In this case it looks like you would want to roll your own exception that matches the problem closer, so that the calling method can correctly recover frm this exception. Maybe a PostConditionException would be generic enough for many circumstances.
是的,没关系,但我认为让它发生是一个更好的决定。
Java 程序员和 null 的问题在于,人们来自 C/C++ 背景,其中 NULL 的含义有很大不同。在 C/C++ 中,取消引用 NULL(或野)指针是一个严重的问题,可能会导致奇怪的内存问题或使程序崩溃(显然不可取)。如果您能够摆脱 C/C++ 的思维方式,并意识到您有这个额外的层,即 JVM,它可以为您处理这种情况,您就会开始以不同的方式思考 NULL。
例如,在 C++ 中,我们有引用,永远不能将其分配为 NULL。在 Java 中,没有引用,但 Java 对象参数的行为更像 C++ 指针。但在 Java 中,有很多情况下,方法不应该隐式接收空值参数!那么,我们该怎么办?
在 Java 中像在 C++ 中那样处理 null 的问题是,这会导致 到处 进行 null 检查,而在 C++ 中,您只需声明一个获取引用的方法,该方法明确指出它不接受 NULL。很快,每个方法都必须进行健全性检查,只是为了断言程序当时的状况,从而造成混乱。
假设方法的默认约定是 null 对参数值无效,这是一种更好的心态。
为什么?好吧,让我们看看当这样的方法接收 null 作为参数值时会发生什么。 a) 也许没问题,因为它不会将值取消引用作为其行为的一部分。在这种情况下,什么也不会发生。 b) 该值被解除引用。在这种情况下,JVM 的行为正是我们想要的:抛出一个异常,表明由于参数值为空而违反了方法的约定,并且它包含一个堆栈跟踪,将我们一路带到以这种方式使用该值的方法中的行。
人们对 NPE 持异议,因为他们认为当你在日志中看到 NPE 时,这意味着“某人搞砸了”。但让我们想一想。作为搞砸的指标,NPE 与预期行为相比,实际上有什么区别?我认为使用 NPE 作为预期行为的主要区别(和优点)是,它不是指向它发生的方法,而是指向违反方法契约的调用者。这是更有用的信息。如果我们只是简单地检查 null 并抛出不同的异常,我们可能会错误地认为观察到的行为是预期的错误,而实际上调用者违反了方法的约定。恭喜,您正确地预期了调用者在调用该方法时可能会搞砸的情况 - 然而,您所做的一切只是让自己误入歧途,不知道异常的真正原因是什么 - 或者最多,您正在使用两个不同的异常类表示同样的事情,同时用不必要的垃圾大量弄脏代码。
因此,归根结底,人们认为 NPE 是禁忌。从字面上看,人们不会允许它被抛出,因为随之而来的是某种羞耻感 - 就好像你不够聪明,因为你没有猜到某个值在哪里会为空。好吧,我给你们带来了消息,你们只是编写了更多无用的代码来完成同样的事情。
一些例子:
^ 政治上不同。从功能上来说,没有那么多。
^ 也许可以节省一些 CPU 周期,但代价是大量烦人的代码。然而,我们对第二种情况进行的比较较少。
^ 契约是从语句中隐含的,而不是方法开头的异常情况。没有其他缺点。
^ 不好
^ 使用 null 返回值来指示不存在值。好的。
人们遇到 NPE 问题的另一个原因是他们不知道如何处理异常。 NPE 永远不应该成为一个搅局者。适当的行为是捕获 RuntimeException,大概是在调用堆栈中更高(或更低,取决于您如何看待它)的级别上捕获它并在“main”之前报告它。也就是说,假设您正在开发一种需要更具弹性的程序,并且在发生 NPE 时不能崩溃。
底线:永远不要指望为方法参数传递空值是有效的。并且绝对不要为显式接受 null 并将其视为有效值的方法创建契约。但是,允许发生空指针异常,并让代码自然地失败,或者在无关紧要的时候不失败。
Yes, it is OK, but I would argue it's a better decision to just let it happen.
The problem with Java programmers and null is that people come from a C/C++ background, where NULL means something a lot different. In C/C++ dereferencing a NULL (or wild) pointer is a serious issue that can cause strange memory issues or crash your program (obvious not desirable). If you can get out of the C/C++ way of thinking and you realize that you have this extra layer, the JVM, which handles this condition for you, you start to think about NULL a little differently.
In C++ we have references, for instance, which can never be assigned NULL. In Java, there are no references, but Java object parameters behave more like C++ pointers. But there are a lot of situations in Java in which a method implicitly should NOT receive a null value for a parameter! So, what do we do?
The problem with treating null in Java like you do in C++ is that this results in null checks EVERYWHERE, whereas in C++ you would simply be declaring a method to take a reference, which explicitly states that it does not accept NULL. Pretty soon every method has to have a sanity check in it just to assert the condition of the program at that point, creating a mess.
It's a much better state of mind to work under the assumption that a method's default contract is that null is invalid for a parameter value.
Why? Well, let's look at what happens when such a method receives null as a parameter value. a) Perhaps it's OK because it does not dereference the value as part of its behavior. In this case, nothing happens. b) The value is dereferenced. In this case, the behavior from the JVM is exactly what we desire: an exception is thrown indicating that the contract of the method has been violated due to a parameter value being null, and it includes a stack trace bringing us all the way to the line in the method where the value is utilized in this way.
People take issue with NPE because they think that when you see NPE in the logs, it means "someone fucked up". But let's think about this for a second. What is actually the difference in NPE as an indicator of fuckup as opposed to expected behavior? I'd argue the major difference (and advantage) of using NPE as expected behavior is that it points not to the method in which it occurred, but to the caller for violating the method's contract. This is much more useful information. If we were to simply check null and throw a different exception, we might be under the false impression that the observed behavior is an expected error, when really the caller is violating the contract of the method. Congratulations, you correctly anticipated how you the caller might screw up in calling the method - however all you've done is led yourself astray as to what the real cause of the exception is - or at best, you're using two different exception classes to indicate the same thing and massively dirtying up the code with unnecessary garbage in the meantime.
So when it comes down to it people consider NPE to be taboo. Literally people will not allow it to be thrown because there's some sense of shame that goes with it - as if you aren't smart enough because you failed to guess where a value would be null. Well, I got news for you guys, you're just writing more useless code to do the same thing.
Some examples:
^ Politically different. Functionally, not so much.
^ Maybe saves a few CPU cycles at the expense of a lot of annoying code. However, we do less comparisons in the second case.
^ The contract is implicit from the statement, rather than an exception case at the beginning of the method. Offers no other disadvantage.
^ Bad
^ Using null return value to indicate the absence of a value. OK.
Another reason people have problems with NPE is because they don't know how to handle exceptions. NPE should never be a showstopper. The appropriate behavior is to catch RuntimeException, presumably at a much higher (or lower, depending how you see it) level in the call stack that traps it and reports it before "main". That is, assuming you're developing the sort of program that needs to be more resilient and can't just crash when an NPE happens.
Bottom line: don't ever expect it's a valid thing to be passing in null values for method parameters. And definitely don't create a contract for a method that explicitly accepts null and treats it as a valid value. But, allow null pointer exceptions to happen, and let the code fail, or not fail when it doesn't matter, naturally.
在逻辑变得太深以至于调用程序员很难弄清楚什么是 null 之前抛出 NPE 通常是一个非常好的主意。 addListener() 方法就是一个很好的例子。
尽管存在不知情的反对意见,但 JDK 中有许多方法可以做到这一点。
It's often a really good idea to throw NPE before the logic gets so deep that the calling programmer will have a hard time figuring out what was null. addListener() methods are a good example.
Uninformed downvotes notwithstanding, there are many methods in the JDK that do exactly this.
在 Java 领域,当需要一个对象时,null 始终是一个有效值。你最好避免这种不可能的后置条件。如果您确实不能忍受 null,那么您将不得不重新设计您的方法,以便可以返回一个原语。
In the Java-verse null is always a valid value when expecting an object. You're better off avoiding such impossible post conditions. If you really can't abide a null then you'll have to rework your method so you can return a primitive.
正如约书亚·布洛赫(Joshua Bloch)曾经说过的:“空很糟糕!” :) 每当我的脸为 null 时,我都会尝试使用 guava 提供的Optional。对我来说优点很多。
As Joshua Bloch once said : "Null sucks!" :) whenever there is null is my face, I try to use the Optional that guava provides. The advantages are numerous to me.
后置条件意味着如果不满足条件,则相关方法存在错误。在代码中表达这一点的方法是在后置条件上使用
assert
。直接抛出异常,例如 NullPointerException 或 IllegalStateException 会有点误导,因此会产生误导。NPE 的 Java API 文档说是,但是从本页上给出的投票来看,3:1 的大多数开发人员表示不。所以我想说这取决于您工作组的惯例。
API 文档首先列出了 JVM 引发 NPE 的情况,因为代码尝试调用需要某种对象的空引用操作(例如调用方法或访问字段),并且
null
不是一个对象。然后它指出:有趣的是,
null
在这里被称为“对象”,但事实并非如此。这提醒我,对于没有指针的语言来说,NullPointerException 这个名字很奇怪。 (在 Microsoft .NET 类库中,这可能应该是NullReferenceException
。)那么我们是否应该就此忽略 API 文档呢?我不这么认为。类库确实使用了文档中描述的 NPE,例如在 java.nio.channels 中:
这不是 JVM 生成的 NPE,而是带有附加错误消息的编码 NPE,指出哪个参数为
null
(例如"in" is null!
)。 (代码可以通过执行javap -c -p java.nio.channels.Channels | more
来查看,寻找private static void checkNotNull
。)并且有很多类以这种方式使用 NPE,本质上是作为 IllegalArgumentException 的特例。因此,在对此进行了一些调查并思考之后,我发现这是 NPE 的一个很好的用途,因此我同意 API 文档和少数 Java 开发人员(根据本页上的投票),即你们都是有权以与 Java 类库相同的方式在自己的代码中使用 NPE,即提供错误消息,而 JVM 生成的 NPE 中明显缺少该消息,这就是为什么区分两种 NPE 没有问题分开。
为了解决 NPE 无论如何都会被扔到更远的地方的小问题:尽早捕获错误而不是让 JVM 继续执行程序是非常有意义的,这可能涉及磁盘或网络 I/O(以及延迟) ),并生成不必要的大堆栈跟踪。
A post-condition means that the method in question has a bug if the condition is not met. The way to express this in code is by using an
assert
on the post-condition. Directly throwing an exception, such as aNullPointerException
or anIllegalStateException
, would be a little misguiding, and hence misguided.The Java API doc for the NPE says yes, but, judging by the votes given on this page, a 3:1 majority of developers says no. So I'd say it depends on the conventions in your workgroup.
The API doc first lists the cases where the JVM raises an NPE because code tries to invoke an operation on a null reference that requires an object of some sort (like calling a method or accessing a field), and
null
is not an object. It then states:Interestingly,
null
is called an »object« here, which it is not. Which reminds me that the very nameNullPointerException
is bizarre for a language that doesn't have pointers. (That should probably have beenNullReferenceException
as in the Microsoft .NET class library.)So should we dismiss the API doc on this count? I don't think so. The class library does use the NPE as described in the docs, for example in
java.nio.channels
:This is not an NPE generated by the JVM, but a coded NPE with an attached error message stating which argument was
null
(like"in" is null!
). (The code can be seen by doingjavap -c -p java.nio.channels.Channels | more
, looking forprivate static void checkNotNull
.) And there are many classes that use NPEs in this fashion, essentially as a special case ofIllegalArgumentException
.So after investigating this a bit and thinking about it, I find this to be a good use of the NPE, and hence I agree with the API doc and the minority of Java developers (as per the votes on this page) that you are both entitled and right to use the NPE in your own code in the same way the Java class library does, that is by providing an error message, which is conspicuously missing from JVM generated NPEs, which is why there's no problem telling the two kinds of NPE apart.
To address the minor point that the NPE will be thrown anyway further down the road: It can very well make sense to catch errors early instead of allowing the JVM to go on with the program, possibly involving disk or network I/O (and delays), and generating an unnecessarily large stack trace.
我同意之前答案中的说法,即 NPE 是代码中的错误,不应抛出,但开发人员应该修复意外的 null。然而,这种状态大多数时候可以通过测试来避免。
这个问题在 7 年前就被问到了,但现在我们在 java 8 中有了可选的功能,这个功能可以防止 NPE。
我想到的最后一个解决方案是,您应该检查对象是否为 null 以及它是否相等,因此抛出您自己的异常并描述所发生的情况。
I agree with claim in the previous answers, that the NPE is bug in code and should not be thrown, but developer should fix unexpected null. However this state can be prevented most of time by tests.
The question was asked before 7 years, but now we have Optional in java 8 and this feature allow to prevent NPE.
The last one solution, which have on my mind is that you should check object on null and if it is equal, so throw your own exception with description of what happened.
在某些情况下,抛出该异常并不是一个好的做法,我想知道为什么当你已经用 if 语句捕获它时?
Throw that exception is not a good practice in some case and I wonder why when you already catch it with the if statement?