Tony Hoare calls null
the “billion-dollar mistake.” It’s a mistake, and that’s why you should get in the habit of forbidding code from using null
. If you have a reference to an object that might be null
, you have to remember to do a null
check before trying to call any method of it. But since there’s no obvious difference between a null
reference and a non-null
one, it’s too easy to forget and get a NullPointerException
.
The most future-proof way to avoid issues is to use an alternative when possible.
It is usually not a good idea to declare a variable until you know what value it should hold. For complex initialization, move all the initialization logic to a method. For example, instead of doing this:
public String getEllipsifiedPageSummary(Path path) { String summary = null; Resource resource = this.resolver.resolve(path); if (resource.exists()) { ValueMap properties = resource.getProperties(); summary = properties.get("summary"); } else { summary = ""; } return ellipsify(summary); }
Do the following:
public String getEllipsifiedPageSummary(Path path) { var summary = getPageSummary(path); return ellipsify(summary); } public String getPageSummary(Path path) { var resource = this.resolver.resolve(path); if (!resource.exists()) { return ""; } var properties = resource.getProperties(); return properties.get("summary"); }
Initializing a variable to null
might leak null
unintentionally if you are not careful with your error-handling code. Another developer might change the control flow without realizing the issue—and that other developer might be you three months after the code was first written.
When you read the signature of a method, you should be able to understand if it always returns a T
or if sometimes it doesn’t. Returning an Optional<T>
is a better option that makes the code more explicit. Optional
’s API makes it very easy to deal with the scenario where no T
was produced.
If you need a T
, ask for it; if you can get by without one, then don’t ask for it. For an operation that can have an optional parameter, create two methods: one with the parameter and one without.
For example, the method drawImage
from the Graphics
class in the JDK has a version that receives five parameters and a sixth parameter, an ImageObserver
, which is optional. If you don’t have an ImageObserver
, you need to pass null
like this:
g.drawImage(original, X_COORD, Y_COORD, IMG_WIDTH, IMG_HEIGHT, null);
It would have been better to have another method with just the first five parameters.
When is it acceptable to use null
, then? As an implementation detail of a class, i.e., the value of an attribute. The code that needs to be aware of that absence of value is contained to the same file, and it’s much more simple to reason about it and not leak null
.
So remember, unless you have an attribute, it’s always possible to avoid using null
using a superior construct in your code. If you stop using null
where you don’t need it, then it becomes impossible to leak null
and have a NullPointerException
. And if you avoid these exceptions, you’ll be part of the solution to the billion-dollar problem instead of being part of it.
18.217.194.39