Saying more than nothing

Estimated read time: 4 min

Originally published on July 23rd, 2012 (Last updated on July 3rd, 2020)

As I was read­ing around on Stack­Over­flow, dig­ging through oth­er peo­ples source code, I spot­ted mul­ti­ple meth­ods return­ing null in a vari­ety of cir­cum­stances. I also found rather imag­i­na­tive ways to han­dle null-values.

Although there is noth­ing wrong with null, the con­cept of null-point­ers seems to be some­what mis­un­der­stood. Let’s change that.

What are null-pointers? #

Wikipedia has the fol­low­ing to say:

A null point­er has a val­ue reserved for indi­cat­ing that the point­er does not refer to a valid object.

In Java, there are two types of vari­ables: val­ue-types and ref­er­ence-types. The first group includes the prim­i­tive data-types like int, float, char and byte. The sec­ond con­tains objects.

Since only ref­er­ence-types can be null (a ref­er­ence to noth­ing), it’s not pos­si­ble to set a val­ue-type to null. Side-Note: In Java, you can set a val­ue-type to null, by using the appro­pri­ate box­ing-type (e.g. Integer, which is a ref­er­ence-type) and set­ting it to null.

When invok­ing a method or access­ing a field on an object with a null ref­er­ence, a NullPointerException will be thrown.

When to use null #

A val­ue of null should only be used when effec­tive­ly say­ing noth­ing. For exam­ple, it might be impor­tant that there is a dif­fer­ence between an emp­ty mes­sage (string ""), and no mes­sage at all (as in the BufferedReader.readLine()-method).

A more prac­ti­cal exam­ple is giv­en in C# in Depth” by Jon Skeet, Chap­ter 4, Say­ing noth­ing with nul­lable types”:

[…] an exam­ple might be an e‑commerce appli­ca­tion where users are look­ing at their account his­to­ry. If an order has been placed but not deliv­ered, there may be a pur­chase date but no dis­patch date […]

In those cas­es, where there is just noth­ing to say about the val­ue, you should use null.

The dan­gers of null #

Let’s take a look at some com­mon anti-pat­terns where null is used inappropriately.

Nev­er use null to indi­cate an error #

Quite often, devel­op­ers tend to return null when some­thing went wrong in the method. Here is a clas­sic example:

// Anti-pattern. DON'T DO THIS!
public Foo readFoo(File file){
    try {
        // Try reading the contents from the given file
        return actualReadData;
    } catch (IOException e){
        e.printStackTrace();
        return null;
    }
}

This code will (giv­en that the read­ing part is actu­al­ly imple­ment­ed) read the con­tents from the passed file-argu­ment, cre­ate a new Foo-object and return it. If how­ev­er the method fails to read the con­tents from the file, it will return null.

This pat­tern is prob­lem­at­ic, as it has to be explic­it­ly doc­u­ment­ed under which cir­cum­stances the method returns null. Oth­er­wise, it’s unclear what the returned null actu­al­ly means. Does it mean the file is emp­ty? Does the file not exist? Was the con­tent not parseable?

Addi­tion­al­ly, it might be pos­si­ble to recov­er from cer­tain fail­ure cas­es, but you can’t dif­fer­en­ti­ate between them when they all just return null (which only tells you that some­thing went wrong). Last but not least, return­ing null does not force any han­dling of the error-con­di­tion. All those draw­backs can be over­come by throw­ing an excep­tion instead.

Yoda Con­di­tions #

As cool as the name sounds, Yoda Con­di­tions” are a dan­ger because they com­plete­ly defeat the pur­pose of mak­ing a val­ue null. Here is an example:

String possiblyNull = possiblyReturnsNull();
if ("constant".equals(possiblyNull)){
    // it equals!
} else {
    // it doesn't.
}

Let’s assume that possiblyReturnsNull() does not return null to indi­cate an error but actu­al­ly, to return noth­ing. Using the Yoda Con­di­tion” avoids a pos­si­ble NullPointerException. But this also indi­cates that: null is the same as every­thing which is not constant”.

Since there’s prob­a­bly a rea­son why possiblyReturnsNull() returns null instead of an actu­al val­ue, you should test for this specif­i­cal­ly. If it does­n’t make a dif­fer­ence if the val­ue is null or any­thing which is not con­stant”, the deci­sion to return null in this case was prob­a­bly a design-error.

Nev­er return null for arrays/​collections #

Let’s say you have a func­tion which returns all Uni­corn-toys still in stock:

// Anti-pattern. DON'T DO THIS!
public List<Unicorns> getUnicorns(){
    if (unicornList.size() == 0){
        return null;
    }
    // ...
}

This case is spe­cial because we want to say that there are cur­rent­ly no uni­corns in stock. So why is this bad?

Con­sid­er a world in which the hypo­thet­i­cal shop usu­al­ly always has Uni­corn-toys in stock. When the call­ing code does not explic­it­ly check for a null return val­ue, it might run as expect­ed for years. Until some­body buys up the entire stock and now the shop is crashing.

So in this case, noth­ing is the same as emp­ty. There­for, you can (and should) return an emp­ty array/​collection, instead of null:

// Return empty arrays/collections instead of null
public List<Unicorns> getUnicorns(){
    if (unicornList.size() == 0){
        return Collections.emptyList();
    }
    // ...
}

This enables the caller of the method to sim­ply iter­ate over the returned list, with­out need­ing to fear a NullPointerException.

You don’t even need to instan­ti­ate a new col­lec­tion, as the Collections-class pro­vides the meth­ods emptySet(), emptyList() and emptyMap() to return an emp­ty, immutable col­lec­tion for the giv­en type of collection.

Con­clu­sion #

To sum it all up:

  • Use null when the val­ue is noth­ing
  • Don’t return null to indi­cate an error!
  • Check for null, if it indi­cates a dif­fer­ent result then not what you’re look­ing for”
  • Don’t return null for emp­ty arrays/​collections

Posted by Lukas Knuth

Comments

No com­ment sec­tion here 😄

You can reach me over at @knuth_dev or send me an Email.