Null is just something you need to deal with in Java. This post looks at the mechanism for handling chained method calls without causing a NullPointerException.
This post uses Java 8.
Beans
Here's a deep object graph for illustration purposes:
public class Root { private Trunk trunk; public Trunk getTrunk() { return trunk; } public void setTrunk(Trunk trunk) { this.trunk = trunk; } public static class Trunk { private Branch branch; public Branch getBranch() { return branch; } public void setBranch(Branch branch) { this.branch = branch; } } public static class Branch { private Leaf leaf; public Leaf getLeaf() { return leaf; } public void setLeaf(Leaf leaf) { this.leaf = leaf; } } public static class Leaf { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } }
Given a Root
reference variable there are a lot of null
checks between it and Leaf.name
:
public static void printLeafName(Root root) { String name = null; if(root != null) { Root.Trunk trunk = root.getTrunk(); if (trunk != null) { Root.Branch branch = trunk.getBranch(); if (branch != null) { Root.Leaf leaf = branch.getLeaf(); if (leaf != null) { name = leaf.getName(); } } } } System.out.println(name); }
Some languages provide facilities for handling this, like Groovy's safe navigation operator:
def void printLeafName(Root root) { def name = root?.trunk?.branch?.leaf?.name System.out.println(name) }
Java lacks such an operator.
Ternary operator
Java's conditional operator
often provides a succinct alternative to if
statements but not in this case:
public static void printLeafName(Root root) { String name = ((root == null) || (root.getTrunk() == null) || (root.getTrunk().getBranch() == null) || (root.getTrunk().getBranch().getLeaf() == null)) ? null : root.getTrunk().getBranch().getLeaf().getName(); System.out.println(name); }
It also comes at the expense of more getter calls, cheap though they are.
Optional
Combining the Java 8 Optional type with method references gives reasonably clear code:
public static void printLeafName(Root root) { String name = Optional.ofNullable(root) .map(Root::getTrunk) .map(Root.Trunk::getBranch) .map(Root.Branch::getLeaf) .map(Root.Leaf::getName) .orElse(null); System.out.println(name); }
The downside here is object allocation.
KλudJe
The KλudJe library takes a tangential approach to using method references to achieve the same thing with the Nullifier type:
public static void printLeafName(Root root) { String name = Nullifier.eval(root, Root::getTrunk, Root.Trunk::getBranch, Root.Branch::getLeaf, Root.Leaf::getName); System.out.println(name); }
The advantage of this example over Optional
is that there are no object allocations because Oracle JDK8 will reuse static method references.
No comments:
Post a Comment
All comments are moderated