Michael Dibbets Michael Dibbets - 6 months ago 27
Java Question

Advantages of using a (flat)map over a simple null check?

I was reading the below source, and I was wondering why on earth I'd use the flatmap way. As I see it a lot more objects are instantiated, code executed than in the simple null check via if statement, which will terminate on the first null and not bother to check the others and fits nice and neatly in wrapper.

As I see it the if check is faster + more memory safe(the speed is really crucial for me as I usually only have 2-3 milliseconds for a shitton of code to execute, if at all)

What are the advantages of using the "(flat)Map" optional way? Why should I consider switching to it?

From http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/

class Outer {
Nested nested;
}

class Nested {
Inner inner;
}

class Inner {
String foo;
}



In order to resolve the inner string foo of an outer instance you have to add multiple null checks to prevent possible NullPointerExceptions:


Outer outer = new Outer();
if (outer != null && outer.nested != null && outer.nested.inner != null) {
System.out.println(outer.nested.inner.foo);
}



The same behavior can be obtained by utilizing optionals flatMap operation:


Optional.of(new Outer())
.flatMap(o -> Optional.ofNullable(o.nested))
.flatMap(n -> Optional.ofNullable(n.inner))
.flatMap(i -> Optional.ofNullable(i.foo))
.ifPresent(System.out::println);

Answer

I think Optional's use would be clearer in a wider streaming context, not a one liner.

Suppose we were dealing with an ArrayList of Outers called items and the requirement is to get a stream of the foo strings if present.

We could do this:

//bad example, read on
Stream<String> allFoos = list.stream()
            .filter(o -> o != null && o.nested != null && o.nested.inner != null)
            .map(o -> o.nested.inner.foo);

But I've had to repeat myself, about how to get the string from an outer (o != null && o.nested != null && o.nested.inner != null and o.nested.inner.foo)

Stream<String> allFoos =
            list.stream()
                    .map(o -> Optional.ofNullable(o)
                            .flatMap(t -> Optional.ofNullable(t.nested))
                            .flatMap(n -> Optional.ofNullable(n.inner))
                            .flatMap(i -> Optional.ofNullable(i.foo)))
                    .filter(s -> s.isPresent())
                    .map(s -> s.get());

This also gives me an easy way to insert default values:

Stream<String> allFoos =
            list.stream()
                    .map(o -> Optional.ofNullable(o)
                            .flatMap(t -> Optional.ofNullable(t.nested))
                            .flatMap(n -> Optional.ofNullable(n.inner))
                            .flatMap(i -> Optional.ofNullable(i.foo))
                            .orElse("Missing"));