This is the most common problem to beginner to intermediate level programmer: they either don't know or don't trust the contracts they are participating in and defensively over check for nulls.
why the codes as follows is ugly?
if( sth != null ) { ... }
It's not ugly as much as you know , but we thought it's extra check and not readable code if we have alot of null
check condition in project. (For the case, if you accept where null is a valid response in terms of the contract; and ...)
But what is null safe or null safty exacty?
Below is my suggestion for "null
safe" way to code according to my experienced and favorite authors.
For Collection Object Case
(1) Return empty arrays or collections, not nulls (Effective Java (See Item 43) - Joshua Bloch )
// The right way to return an array from a collection
private final List cheesesInStock = ...;
private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0];
/**
* @return an array containing all of the cheeses in the shop.
*/
public Cheese[] getCheeses() {
return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY);
}
In similar fashion, a collection-valued method can be made to return the same
immutable empty collection every time it needs to return an empty collection. The Collections.emptySet
, emptyList
, and emptyMapmethods
provide exactly what you need, as shown below:
// The right way to return a copy of a collection
public List getCheeseList() {
if (cheesesInStock.isEmpty())
return Collections.emptyList(); // Always returns same list
else
return new ArrayList(cheesesInStock);
}
In summary, there is no reason ever to return null
from an array
- or
collection
-valued method instead of returning an empty array or collection.
(2) Don't Return Null - (Clean Code - Uncle Bob)
In many cases, special case objects are an easy remedy. Imagine that you have code like this:
List employees = getEmployees();
if (employees != null) {
for(Employee e : employees) {
totalPay += e.getPay();
}
}
Right now, getEmployees
can return null
, but does it have to? If we change getEmployeeso
that it returns an empty list, we can clean up the code:
List employees = getEmployees();
for(Employee e : employees) {
totalPay += e.getPay();
}
Fortunately, Java
has Collections.emptyList()
, and it returns a predefined immutable list that we can use for this purpose:
public List getEmployees() {
if( .. there are no employees .. )
return Collections.emptyList();
}
If you code this way, you will minimize the chance of NullPointerExceptions
and your code will be cleaner.
Don’t Pass Null
Returning null
from methods is bad, but passing null
into methods is worse. Unless you are working with an API which expects you to pass null
, you should avoid passing null
in your code whenever possible.
Let’s look at an example to see why. Here is a simple method which calculates a metric for two points:
public class MetricsCalculator
{
public double xProjection(Point p1, Point p2) {
return (p2.x – p1.x) * 1.5;
}
…
}
What happens when someone passes null
as an argument?
calculator.xProjection(null, new Point(12, 13));
We’ll get a NullPointerException
, of course.
How can we fix it? We could create a new exception type and throw it:
public class MetricsCalculator
{
public double xProjection(Point p1, Point p2) {
if (p1 == null || p2 == null) {
throw InvalidArgumentException(
"Invalid argument for MetricsCalculator.xProjection");
}
return (p2.x – p1.x) * 1.5;
}
}
Is this better? It might be a little better than a nullpointerexception
, but remember, we have to define a handler for InvalidArgumentException
. What should the handler do? Is there any good course of action?
There is another alternative. We could use a set of assertions:
public class MetricsCalculator
{
public double xProjection(Point p1, Point p2) {
assert p1 != null : "p1 should not be null";
assert p2 != null : "p2 should not be null";
return (p2.x – p1.x) * 1.5;
}
}
It’s good documentation, but it doesn’t solve the problem. If someone passes null, we’ll still have a runtime
error.
In most programming languages there is no good way to deal with a null
that is
passed by a caller accidentally. Because this is the case, the rational approach is to forbid passing null by default. When you do, you can code with the knowledge that a null
in an argument list is an indication of a problem, and end up with far fewer careless mistakes.
Extra Note:
The null
-return idiom is likely a holdover from the C programming language, in which array lengths are returned separately from actual arrays. In C, there is no advantage to allocating an array if zero is returned as the length.
For Non-Collection Object Case
(1) Use Null Object Pattern (old approach)
eg.(assume you are using dao pattern to access db)
All you need to do is return an empty object - say a customer entry you would have in your DAO something like.....
if (result == null) { return new EmptyUser(); }
where EmptyUser
extends User
and returns appropriate entries to getter calls to allow the rest of your code to know it is an empty object (id = -1 etc)
code sample:
public class User {
private int id;
private String name;
private String gender;
public String getName() {
//Code here
}
public void setName() {
//Code here
}
}
public class EmptyUser extends User {
public int getId() {
return -1;
}
public String getName() {
return String.Empty();
}
}
public User getEntry() {
User result = db.query("select from users where id = 1");
if(result == null) {
return new EmptyUser();
}
else {
return result;
}
}
(2) Use Java 8 Optional
Indeed introducing null
reference is probably one of the worse mistake in the programming languages' history even its creator Tony Hoare calls it his billion-dollar mistake.
Here are the best alternatives to null
according to new Java
version:
2.1. Java 8
and above
Starting from Java 8
you can use java.util.Optional.
Here is an example of how you could use it in not null return case:
public Optional findMyEntity() {
MyEntity entity = // some query here
return Optional.ofNullable(entity);
}
2.2. Prior to Java 8
Before Java 8
you can use com.google.common.base.Optional from Google Guava.
Here is an example of how you could use it in not null return case:
public Optional findMyEntity() {
MyEntity entity = // some query here
return Optional.fromNullable(entity);
}
Note for Null Object Pattern Vs Java 8 Optional
:
I definitively prefer Optional
it is much more generic
and it has been adopted by Oracle and Google, 2 of the biggest IT companies in the world which give a lot of credits to it.
I would even say that Null Object Pattern doesn't make any sense anymore in Java
, it is outdated, Optional
is the future if you check a little bit what's new in Java 9, you will see that Oracle makes Optional
go a little bit further, read this article