103

Let's say I'd like to perform the following command:

house.getFloor(0).getWall(WEST).getDoor().getDoorknob(); 

To avoid a NullPointerException, I'd have to do the following if:

if (house != null && house.getFloor(0) && house.getFloor(0).getWall(WEST) != null && house.getFloor(0).getWall(WEST).getDoor() != null) ... 

Is there a way or an already existing Utils class that does this more elegantly, let's say something like the following?

checkForNull(house.getFloor(0).getWall(WEST).getDoor().getDoorknob()); 
10
  • 6
    If only you followed the law of Demeter. Commented Aug 11, 2010 at 12:59
  • 41
    Just because I started working on an existing project, I can't redesign it according to my or any Greek deity's law. Commented Aug 11, 2010 at 13:06
  • 1
    For anyone else wondering: "In particular, an object should avoid invoking methods of an object returned by another method. ...the law can be stated simply as 'use only one dot'" en.wikipedia.org/wiki/Law_of_Demeter Commented Nov 12, 2021 at 13:59
  • 3
    The Law of Demeter is a terrible idea (which is why, thankfully, nobody uses it!). Leads to error-prone gobbledegook code. It's also anti-intuitive: if every instinct is telling you not to write classes like that, you probably shouldn't. But I really don't see how it would help null safe chaining anyway. It just pushes the multiple null checks into the method House::getDoorknob(Floor floor, CompassPoint wall, DoorType doorType). And the un-useability of that monstrous method says it all. Commented Jul 27, 2022 at 11:48
  • 1
    My point being, it's a bad way to design classes. The intuitive design is pretty much always the best design. The design which presents the data to you in the way you expect data to be presented to you is the best design. The design which matches the way humans think about entities and their properties (that they are chained) is the best design. The LoD is the opposite of good design. Commented Nov 11, 2022 at 13:12

11 Answers 11

162

In case you can't avoid breaking Law of Demeter (LoD) as stated in the chosen answer, and with Java 8 introducing Optional, it would be probably the best practice to handle nulls in chains of gets such as yours.

The Optional type will enable you to pipe multiple map operations (which contain get calls) in a row. Null checks are automatically handled under the hood.

For example, when the objects aren't initialized, no print() will be made and no Exceptions will be thrown. It all we be handled gently under the hood. When objects are initialized, a print will be made.

System.out.println("----- Not Initialized! -----"); Optional.ofNullable(new Outer()) .map(out -> out.getNested()) .map(nest -> nest.getInner()) .map(in -> in.getFoo()) .ifPresent(foo -> System.out.println("foo: " + foo)); //no print System.out.println("----- Let's Initialize! -----"); Optional.ofNullable(new OuterInit()) .map(out -> out.getNestedInit()) .map(nest -> nest.getInnerInit()) .map(in -> in.getFoo()) .ifPresent(foo -> System.out.println("foo: " + foo)); //will print! class Outer { Nested nested; Nested getNested() { return nested; } } class Nested { Inner inner; Inner getInner() { return inner; } } class Inner { String foo = "yeah!"; String getFoo() { return foo; } } class OuterInit { NestedInit nested = new NestedInit(); NestedInit getNestedInit() { return nested; } } class NestedInit { InnerInit inner = new InnerInit(); InnerInit getInnerInit() { return inner; } } class InnerInit { String foo = "yeah!"; String getFoo() { return foo; } } 

So, with your getters chain it will look like this:

Optional.ofNullable(house) .map(house -> house.getFloor(0)) .map(floorZero -> floorZero.getWall(WEST)) .map(wallWest -> wallWest.getDoor()) .map(door -> wallWest.getDoor()) 

The return of it will be something like Optional<Door> which will allow you much safer work without worrying of null exceptions.

Sign up to request clarification or add additional context in comments.

4 Comments

Neat trick! like a builder of optionals, any link missing in the chain will cause the chain to stop and make the Optional contain null.
This should be the correct answer, to be honest, and not the current one! Thanks for the great explanation.
This is the correct way to do it if you have Java 8+ available. At the end of the Optional chain you can still do .orElse(null); if you need to pass or otherwise handle a non-Optional type. There is really no downside to chaining ofNullable/map and this should be the accepted answer.
Alien magic !!!
26

In order to check a chain of gets for null you may need to call your code from a closure. The closure call code will look like this:

public static <T> T opt(Supplier<T> statement) { try { return statement.get(); } catch (NullPointerException exc) { return null; } } 

And you call it using the following syntax:

Doorknob knob = opt(() -> house.getFloor(0).getWall(WEST).getDoor().getDoorknob()); 

This code is also type safe and in general works as intended:

  1. Returns an actual value of the specified type if all the objects in the chain are not null.
  2. Returns null if any of the objects in the chain are null.

You may place opt method into shared util class and use it everywhere in your application.

4 Comments

No doubt that it is a really tricky way to handle this case but it is a very bad practice to handle null pointer exception as you might end up handling something unintended. You can read the relevant parts of effective java to get a better understanding.
Isn't NullpointerException expensive than a null check ?
Don't resort to this unless you are using a really old version of Java (<8 where Optional isn't available). See the answer involving Optional.ofNullable()/.map()
This approach is effective when you have a complex data structure, where the majority of the data is optional. Like accessing nested JAXB xml elements. 2 things though: Using .getFloor(0), I'd also handle IndexOutOfBoundsException the same way. Returning with an Optional<T> would be more elegant.
12

The best way would be to avoid the chain. If you aren't familiar with the Law of Demeter (LoD), in my opinion you should. You've given a perfect example of a message chain that is overly intimate with classes that it has no business knowing anything about.

Law of Demeter: http://en.wikipedia.org/wiki/Law_of_Demeter

1 Comment

This answer gives no guidance on how to avoid the chain, and assumes that OP has the time/permission to redesign the existing code.
9

You could of course simply wrap the whole expression up in a try-catch block, but that's a bad idea. Something cleaner is the Null object pattern. With that, if your house doesn't have floor 0, it just returns a Floor that acts like a regular Floor, but has no real content; Floors, when asked for Walls they don't have, return similar "Null" Walls, etc, down the line.

5 Comments

But if a wall doesn't have a door, then returning null is the logical thing to do. Otherwise you will require methods like hasDoor() to know that there is no actual door, since you are just going to get a fake one when you ask for it.
@Robin, it's not exactly a "fake" wall. It's the wall that isn't, that doesn't exist. And (unlike null) it behaves like a real wall, so it's useful in ways that null can't be.
Using the Null Object pattern is a good option if you don't care whether in the end something will happen or not (+1 for that)
So basically, you convert a "fail fast" NPE into a "maybe fail at an unspecified later time and place"? There are some cases where null objects make sense (empty collections, most prominently), but IMO they're totally unfit as a general replacement for null.
No, I expect there to be a wall, but not necessarily a door (to get picky). I was describing the problem with this approach in the particular example since not all walls will contain doors and the ability to determine if there is a door is made more complicated with the Null Object pattern. @Michael Borgwardt describes the issue in the general sense in his comment. My experience has been that this pattern is rather limited in the applications to which it can be applied.
4

Make sure things that can't logically be null are not. For example - a house always has a West wall. In order to avoid such exceptions in state, you can have methods to check whether the state you expect is present:

if (wall.hasDoor()) { wall.getDoor().etc(); } 

This is essentially a null-check, but might not always be.

The point is that you should do something in case you have a null. For example - return or throw an IllegalStateException

And what you shouldn't do - don't catch NullPointerException. Runtime exceptions are not for catching - it is not expected that you can recover from them, nor it is a good practice to rely on exceptions for the logic flow. Imagine that you actually don't expect something to be null, and you catch (and log) a NullPointerException. This will not be very useful information, since many things can be null at that point.

Comments

4

Better solution for me is to use java.util.Optional.map(..) to chain these checks : https://stackoverflow.com/a/67216752/1796826

1 Comment

Yes, this is covered well in answer stackoverflow.com/a/41145698/211614
1

There is no checkForNull method that you can write that will facilitate this (that's simply not how method invokation and argument evaluation works in Java).

You can break down the chained statements into multiple statements, checking at every step. However, perhaps a better solution is to not have these methods return null in the first place. There is something called the Null Object Pattern that you may want to use instead.

Related questions

Comments

1

You could potentially have a generic method like below:

public static <T> void ifPresentThen(final Supplier<T> supplier, final Consumer<T> consumer) { T value; try { value = supplier.get(); } catch (NullPointerException e) { // Don't consume "then" return; } consumer.accept(value); } 

So now you would be able to do

ifPresentThen( () -> house.getFloor(0).getWall(WEST).getDoor().getDoorknob(), doorKnob -> doSomething()); 

Comments

-1

implementing nullPointer try/catch with a Supplier you can send it all chain of get

public static <T> T getValue(Supplier<T> getFunction, T defaultValue) { try { return getFunction.get(); } catch (NullPointerException ex) { return defaultValue; } } 

and then call it in this way.

ObjectHelper.getValue(() -> object1.getObject2().getObject3().getObject4())); 

2 Comments

I forgot... T defaultValue for send a default value when calling it, or remove to return directly null
how is this different than Seleznov's answer above?
-3
// Example LazyObject.from(curr).apply(A.class, A::getB).apply(B.class, B::getC).apply(C.class, C::getD).to(String.class); // LazyObject.java public class LazyObject { private Object value; private LazyObject(Object object) { this.value = object; } public <F, T> LazyObject apply(Class<F> type, Function<F, T> func) { Object v = value; if (type.isInstance(v)) { value = func.apply(type.cast(v)); } else { value = null; // dead here } return this; } public <T> void accept(Class<T> type, Consumer<T> consumer) { Object v = value; if (type.isInstance(v)) { consumer.accept(type.cast(v)); } } public <T> T to(Class<T> type) { Object v = value; if (type.isInstance(v)) { return type.cast(v); } return null; } public static LazyObject from(Object object) { return new LazyObject(object); } } 

3 Comments

please add explanation it would be helpful.
it will throw an NullPointer i.e: A::getB
And why all this casting? This just looks like a very broken attempt to avoid creating a few intermediate objects.
-3

Very old question, but still adding my suggestion:

I would suggest instead of getting the DoorKnob from deep within the House in one method call chain, you should try to let the DoorKnob be provided to this class from the calling code, or by creating a central lookup facility specifically for this purpose (e.g. a DoorKnob service)

Simplified example of design with loose coupling:

class Architect { FloorContractor floorContractor; void build(House house) { for(Floor floor: house.getFloors()) { floorContractor.build(floor); } } } class FloorContractor { DoorMaker doorMaker; void build(Floor floor) { for(Wall wall: floor.getWalls()) { if (wall.hasDoor()) { doorMaker.build(wall.getDoor()); } } } } class DoorMaker { Tool tool; void build(Door door) { tool.build(door.getFrame()); tool.build(door.getHinges()); tool.build(door.getDoorKnob()); } } 

Comments