Try-catch instead of null check when using multiple getters

My problem is this: I have a rather long getter, i.e.

objectA.getObjectB().getObjectC().getObjectD().getObjectE().getName(); 

Due to the poor database / entity architecture (some things were introduced later than others), it happens that getObjectB() , getObjectC() or getObjectD() can return NULL .

Usually we use null checks all the time, but in this case I would have to use

 ObjectB b = objectA.getObjectB(); if (b != null) { ObjectC c = b.getObjectC(); if (c != null) { ObjectD d = c.getObjectD(); if (d != null) return d.getObjectE().getName(); } } return ""; 

Instead, it would be much easier to use a try-catch block.

 try { return objectA.getObjectB().getObjectC().getObjectD().getObjectE().getName(); } catch (NullPointerException e) { return ""; } 

In this case, I don’t care which object returns NULL, it either displays the name or not. Are there any complications or poor design for using try-catch instead of checks?

Thanks for your input.

+8
java
source share
3 answers

If this is a use case for Java 8, you can use Optional as follows:

 Optional.ofNullable(objectA) .map(a -> a.getObjectB()) .map(b -> b.getObjectC()) .map(c -> c.getObjectD()) .map(d -> d.getObjectE()) .map(e -> e.getName()) .orElse(""); 
+7
source share

This type of method chain is called Train Link and is not preferred. This expression also violates the Law of Demeter . Let me give you an example from Robert C. Martin's Clean Code book:

 String scratchDirPath = ctxt.getOptions().getScratchDir().getAbsolutePath(); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(scratchDirPath)); //write to file... 

This is similar to what you have, and this is bad practice. It is possible to at least refactor below:

 Options options = ctxt.getOptions(); File scratchDir = options.getScratchDir(); String scratchDirPath = scratchDir.getAbsolutePath(); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(scratchDirPath)); //write to file... 

This still violates the Law of Demeter, but at least partially better. The most preferred way would be to find out why scratchDirPath is needed and ask the ctxt object to provide it to you. So it will look like

 BufferedOutputStream bos = ctxt.createScratchDirFileStream(); 

Thus, ctxt does not reveal all of its internal elements. This separates the calling code from the ctxt implementation.

+4
source share

This is really a decision that only you and your team can make, but there is (at least) one objective thing that I will call: In the case when one of these methods returns null , your first block of code will perform better than yours second. Throwing an exception is an expensive relatively simple branch. (In the case where none of the methods returns null , I think the second can be almost immeasurably faster than the second, since you avoid branching.) In any case, if performance matters, check it in your environment. (But check it correctly ; micro-tests are complicated. Use tools.)

In most cases, the difference will not matter in the real world, but it is a significant difference at runtime.

0
source share

All Articles