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.