2

I have the following nested null check which. Trying to make it readable via Optional but how do I map a first element?

Stuck with following, unsure how to map this line

vo.getSomething().getAnother().get(0)

I am stuck on the 3rd line

Optional.of(vo.getSomething)
    .map(Something::getAnother)
    .map(List<Another>::get(0)) // will not work

Here is a working null check. I am trying to clean it up with Optional.

if(vo.getSomething() != null){
    if(vo.getSomething().getAnother() != null){
        if(vo.getSomething().getAnother().get(0) != null){
            if(vo.getSomething().getAnother().get(0).getInner() != null){
                if(vo.getSomething().getAnother().get(0).getInner() != null){
                    if(vo.getSomething().getAnother().get(0).getInner().get(0) != null){
                        return vo.getSomething().getAnother().get(0).getInner().get(0).getProductName();
                    }
                }
            }
        }
    }
}
Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
karvai
  • 2,417
  • 16
  • 31
  • 1
    Possible duplicate of [Null check chain vs catching NullPointerException](https://stackoverflow.com/questions/37960674/null-check-chain-vs-catching-nullpointerexception) – Oleksandr Pyrohov Sep 17 '19 at 10:29
  • 3
    @OleksandrPyrohov the accepted answer there is exactly what the OP is doing, so I presume they are aware of that approach. The question is about how to make `List::get(0)` work – Andrew Tobilko Sep 17 '19 at 10:35
  • 1
    This poor design should be fixed not by `Optional`, but by refactoring all that nesting. – Kayaman Sep 17 '19 at 10:48
  • @Kayaman How could we refactor that.. .That is a json response being captured in that structure from an external api... – karvai Sep 17 '19 at 10:49
  • 1
    @karvai several ways. You don't think it's suboptiomal that you do 6 null checks just to get a single productname? – Kayaman Sep 17 '19 at 10:52
  • @Kayaman It is but unable to see how I could do it considering thats the structure that gets passed back to me. I need to capture all those details which are used in different places. Would be great to get some ideas. – karvai Sep 17 '19 at 10:56
  • In the process of copying the code here, seems like you've pasted `if(vo.getSomething().getAnother().get(0).getInner() != null)` twice. Or else you have a redundant branch. – Naman Sep 17 '19 at 11:00
  • @karvai well, for example there's [JSONPath](https://stackoverflow.com/questions/8481380/is-there-a-json-equivalent-of-xquery-xpath) which would get rid of all null checks in **this** case, as you'd be using a path to access the (possible) data of interest. Other techniques involve mapping the JSON to something simpler before manipulating it in code. – Kayaman Sep 17 '19 at 11:02
  • @Naman That was just a typo on my part here. It's correct in my code. – karvai Sep 17 '19 at 11:39
  • @Kayaman Thanks will have a look. – karvai Sep 17 '19 at 11:40

1 Answers1

5

A lambda expression

.map(list -> list.get(0))

should work. Some ideas can't be expressed by method references.

List<Another>::get(0) isn't a valid method reference while List<Another>::get can be.

BiFunction<List<String>, Integer, String> function = List::get;

The problem with that expression is that it has a constant 0 and you need to pass it explicitly.

However, you could write a static method

class ListFunctions {
    public static <T> T getFirst(List<? extends T> list) {
        return list.get(0);
    }
}

and refer to it via a method reference

.map(ListFunctions::getFirst)
Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142