I work with Java all day long. The most used idiom (code snippet) I'm programming in Java, is to test if an object != null
before I use it, to avoid a NullPointerException of course. But the code looks very ugly and becomes unreadable.
Is there a good alternative to avoid this code snippet?
Update: Pan, I was not clear with my question. I want to address the necessity to test every object if you want to access a field or method of this object. For example:
...
if (someobject != null)
{
someobject.doCalc();
}
...
in case I want avoid NullPointerException
and didn't know exactly that the object can't be null. So my code get splattered with these tests.
Nevertheless thanks a lot for your answers, I got a bunch of new insight.
Source: Tips4all
This to me sounds like a reasonably common problem that junior to intermediate developers tend to face at some point: they either don't know or don't trust the contracts they are participating in and defensively overcheck for nulls. Additionally, when writing their own code, they tend to rely on returning nulls to indicate something thus requiring the caller to check for nulls.
ReplyDeleteTo put this another way, there are two instances where null checking comes up:
Where null is a valid response in terms of the contract; and
Where it isn't a valid response.
(2) is easy. Either use assert statements (assertions) or allow failure (for example, NullPointerException). Assertions are a highly-underused Java feature that was added in 1.4. The syntax is:
assert *<condition>*
or
assert *<condition>* : *<object>*
where <object>'s toString() output will be included in the error.
An assert statement throws an Error (AssertionError) if the condition is not true. By default, Java ignores assertions. You can enable assertions by passing the option -ea to the JVM. You can enable and disable assertions for individual classes and packages. This means that you can validate code with the assertions while developing and testing, and disable them in a production environment, although my testing has shown next to no performance impact from assertions.
Not using assertions in this case is OK because the code will just fail, which is what will happen if you use assertions. The only difference is that with assertions it might happen sooner, in a more-meaningful way and possibly with extra information, which may help you to figure out why it happened if you weren't expecting it.
(1) is a little harder. If you have no control over the code you're calling then you're stuck. If null is a valid response, you have to check for it.
If it's code that you do control, however (and this is often the case), then it's a different story. Avoid using nulls as a response. With methods that return collections, it's easy: return empty collections (or arrays) instead of nulls pretty much all the time.
With non-collections it might be harder. Consider this as an example: if you have these interfaces:
public interface Action {
void doSomething();
}
public interface Parser {
Action findAction(String userInput);
}
where Parser takes raw user input and finds something to do, perhaps if you're implementing a command line interface for something. Now you might make the contract that it returns null if there's no appropriate action. That leads the null checking you're talking about.
An alternative solution is to never return null and instead do something like this:
public class MyParser implements Parser {
private static Action DO_NOTHING = new Action() {
public void doSomething() { /* do nothing */ }
};
public Action findAction(String userInput) {
// ...
if ( /* we can't find any actions */ ) {
return DO_NOTHING;
}
}
}
Compare:
Parser parser = ParserFactory.getParser();
if (parser == null) {
// now what?
// this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
// do nothing
} else {
action.doSomething();
}
to
ParserFactory.getParser().findAction(someInput).doSomething();
which is a much better design because it leads to more concise code.
Null Object pattern.
ReplyDeleteIf null-values is not allowed
ReplyDeleteIf your method called externally, start with something like this:
public void method(Object object) {
if (object == null) {
throw new IllegalArgumentException("...");
}
In the rest of that method, you know that it's not null.
If it is an internal method (not part of an api), just document that it cannot be null, and that's it. Example:
public String getFirst3Chars(String text) {
return text.subString(0, 3);
}
However, if your method just passes the value on, and the next method passes on etc. it could get problematic. In that case you may want to check the argument as above.
If null is allowed
This really depends. If find that I often do something like this:
if (object == null) {
// something
} else {
// something else
}
So I branch, and do two completely different things. There is no ugly code snippet, because I really need to do two different things depending on the data. For example, should I work on the input, or should I calculate a good default value?
It's actually rare for me to use the idiom "if (object != null && ...".
It may be easier to give you examples, if you show examples of where you typically use the idiom.
If you use (or planning to use) JetBrains Idea, a Java ide, you can use some particular annotations developed by them.
ReplyDeleteBasically, you've got:
@Nullable
and
@NotNull
You can use in method and parameters, like this:
@NotNull public static String helloWorld() {
return "Hello World";
}
or
@Nullable public static String helloWorld() {
return "Hello World";
}
The second example won't compile (in Idea).
When you use the first HelloWorld() function in another piece of code:
public static void main(String[] args)
{
if(helloWorld() != null) {
System.out.println(helloWorld());
}
}
Now the idea compiler will tell you that the check is useless, since the HelloWorld() function won't return null, ever.
Using parameter
void someMethod(@NotNull someParameter) { }
if you write something like:
someMethod(null);
This won't compile.
Last example using @Nullable
@Nullable iWantToDestroyEverything() { return null; }
Doing this
iWantToDestroyEverything().something();
And you can be sure that this won't happen. :)
It's a nice way to let the compiler check something more than it usually does and to enforce your contracts to be stronger. Unfortunately, it's not supported by all the compilers.
In IntelliJ 10.5 and on, they added support for any other @Nullable @NotNull implementations.
http://blogs.jetbrains.com/idea/2011/03/more-flexible-and-configurable-nullublenotnull-annotations/
If you consider an object should not be null (or it is a bug) use an assert.
ReplyDeleteIf your method doesn't accept null params say it in the javadoc and use an assert.
You have to check for object != null only if you want to handle the case where the object may be null...
There is a proposal to add new annotations in Java7 to help with null / notnull params:
http://tech.puredanger.com/java7/#jsr308
If you can, consider using Scala, it introduces the Option Pattern (may be familiar from functional languages) for this. It mainly has two advantages:
ReplyDeleteIt is stated explicitly in the API whether a result exists or not.
Option is a monad, so there is no need for verbose null checking, just use map/foreach/getOrElse or a similar combinator to safely use the value (example).
If you have to stick with Java, use FunctionalJava's Option, it implements Iterable so at least you can use concise for loops instead of null checks. Read more here and here.
Depending on what kind of objects you are checking you may be able to use some of the classes in the apache commons such as: apache commons lang and apache commons collections
ReplyDeleteExample:
String foo;
...
if( StringUtils.isBlank( foo ) ) {
///do something
}
or (depending on what you need to check):
String foo;
...
if( StringUtils.isEmpty( foo ) ) {
///do something
}
The StringUtils class is only one of many; there are quite a few good classes in the commons that do null safe manipulation.
Wow, I almost hate to add another answer when we have 57 different ways to recommend the NullObject pattern, but I think that some people interested in this question may like to know that there is a proposal on the table for Java 7 to add "null-safe handling"—a streamlined syntax for if-not-equal-null logic.
ReplyDeleteThe example given by Alex Miller looks like this:
public String getPostcode(Person person) {
return person?.getAddress()?.getPostcode();
}
The ?. means only de-reference the left identifier if it is not null, otherwise evaluate the remainder of the expression as null. Some people, like Java Posse member Dick Wall and the voters at Devoxx really love this proposal, but there is opposition too, on the grounds that it will actually encourage more use of null as a sentinel value.
Update: An official proposal for a null-safe operator in Java 7 has been submitted under Project Coin. The syntax is a little different than the example above, but it's the same notion.
Update: The null-safe operator proposal didn't make it into Project Coin. So, you won't be seeing this syntax in Java 7.
Rather than Null Object Pattern -- which has its uses -- you might consider situations where the null object is a bug.
ReplyDeleteWhen the exception is thrown, examine the stack trace and work through the bug.
The google collections framework offers a good and elegant way to achieve the null check.
ReplyDeleteThere is a method in a library class like this:
static <T> T checkNotNull(T e){
if(e == null){
throw new NullPointerException();
}
return e;
}
And the usage is (with import static):
...
void foo(int a, Person p){
if(checkNotNull(p).getAge() > a){
...
}else{
...
}
}
...
or in your example:
checkNotNull(someobject);
someobject.doCalc();
sometimes, you have methods that operate on its parameters that define a symmetric operation:
ReplyDeletea.f(b); <-> b.f(a);
if you know b can never be null, you can just swap it. most useful for equals:
instead of foo.equals("bar"); better do "bar".equals(foo);
Ultimately, the only way to completely solve this problem is by using a different programming language:
ReplyDeleteIn Objective-C, you can do the equivalent of invoking a method on nil, and absolutely nothing will happen. This makes most null checks unnecessary but can make errors much harder to diagnose.
In Nice, a Java-derivated language, there are two versions of all types: a potentially-null version and a not-null version. You can only invoke methods on not-null types. Potentially-null types can be converted to not-null types through explicit checking for null. This makes it much easier to know where null checks are necessary and where they aren't.
In addition to using assert you can use the following :
ReplyDeleteif (someobject == null) {
// handle null here then move on.
}
This is slightly better than :
if (someobject != null) {
.....
.....
.....
}
Only for this situation -
ReplyDeleteAvoiding checking for null before a string compare:
if ( foo.equals("bar") ) {
// ...
}
will result in a NullPointerException if foo doesn't exist.
You can avoid that if you compare your Strings like this:
if ( "bar".equals(foo) ) {
// ...
}
Asking that question points out that you may be interested in error handling strategies. Your team's architect should decide how to work errors. There are several ways to do this:
ReplyDeleteallow the Exceptions to ripple through - catch them at the 'main loop' or in some other managing routine.
check for error conditions and handle them appropriately
Sure do have a look at Aspect Oriented Programming, too - they have neat ways to insert if( o == null ) handleNull() into your bytecode.
Common "problem" in Java indeed.
ReplyDeleteFirst, my thoughts on this:
I consider that it is bad to "eat" something when NULL was passed where NULL isn't a valid value. If you're not exiting the method with some sort of error then it means nothing went wrong in your method which is not true. Then you probably return null in this case, and in the receiving method you again check for null, and it never ends, and you end up with "if != null", etc..
So, imho, null must be a critical error which prevents further execution (i.e. where null is not a valid value).
The way I solve this problem is this:
First, I follow this convetion:
all public methods / API always check for null its arguments
all private methods do not check for null since they are controlled methods (just let die with NPE in case it wasn't handled above)
the only other methods which do not check for null are utility methods. They are public, but if you call them for some reason, you know what parameters you pass. This is like trying to boil water in the kettle without providing water...
And finally, in the code, the first line of the public method goes like this:
ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();
note that addParam() returns self, so that you can add more params to check.
method validate() will throw checked ValidationException if any of the params is null (checked or unchecked is more a design/taste issue, but my ValidationException is checked).
void validate() throws ValidationException;
The message will contain the following text if, for example, "plans" is null:
"Illegal argument value null is encountered for parameter [plans]"
As you can see, 2nd value in the addParam() method (string) is needed for the user message, because you cannot easily detect passed-in variable name, even with reflection (not subject of this post anyway...).
And yes, we know that beyond this line we will no longer encounter a null value so we just safely invoke methods on those objects.
This way, code is clean, easy maintainable and readable.
I'm a fan of "fail fast" code. Ask yourself - are you doing something useful in the case where the parameter is null? If you don't have a clear answer for what your code should do in that case... I.e. it should never be null in the first place, then ignore it and allow a NullPointerException to be thrown. The calling code will make just as much sense of an NPE as it would an IllegalArgumentException, but it'll be easier for the developer to debug and understand what went wrong if an NPE is thrown rather than your code attempting to execute some other unexpected contingency logic - which ultimately results in the application failing anyway.
ReplyDeleteLook at "Null Object" pattern.
ReplyDeleteNull Objects
ReplyDeleteYou can use the Null Object design pattern.
ReplyDeleteCheck this - DefaultIfNull from Apache ObjectUtils.
ReplyDelete