Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing repetitive get statement with Java 8 Optional

I have a use case, where I have nested classes and an object of the top class. I want to get a value which is at the Nth level. I'm using getters repetitively to achieve this to avoid NPE. Sample code (assuming getters are there)

class A {
    String a1;
    String getA1() {
        return a1;
    }
}

class B {
    A a;
    A getA() {
        return a;
    }
}

class C {
    B b;
    B getB() {
        return b;
    }
}

class D {
    C c;
    C getC() {
        return c;
    }
}

If I have an object d of class D, and want to get the String a1 of A, what I'm doing is following:

String getAValue(D d) {
    String aValue = null;
    if(d != null && d.getC() != null && d.getC().getB() != null && d.getC().getB().getA() != null) {
        aValue = d.getC().getB().getA().getA1();
    }
    return aValue;
}

This repetitive a is looking really ugly. How do I avoid it by using java8 Optional?

EDIT: I can't modify the above classes. Assume this d object is returned to me as a service call. I'm exposed to these getters only.

like image 711
AKB Avatar asked Sep 16 '15 03:09

AKB


2 Answers

Use Optional with a series of map() calls for a nice one-liner:

String getAValue(D d) {
   return Optional.ofNullable(d)
       .map(D::getC).map(C::getB).map(B::getA).map(A::getA1).orElse(null);
}

If anything is null along the chain, including d itself, the orElse() will execute.

like image 154
Bohemian Avatar answered Nov 17 '22 20:11

Bohemian


Wrap each nested class in an Optional:

Class A {
    String a1;
}
Class B {
    Optional<A> a;
}
Class C {
    Optional<B> b;
}
Class D {
    Optional<C> c;
}

Then use flatMap and map to operate on these optional values:

String a1 = d.flatMap(D::getC) // flatMap operates on Optional
             .flatMap(C::getB) // flatMap also returns an Optional
             .flatMap(B::getA) // that's why you can keep calling .flatMap()
             .map(A::getA1)    // unwrap the value of a1, if any
             .orElse("Something went wrong.") // in case anything fails

You might want to check out the concept of Monads. And if you're feeling adventurous, Scala is too distant from Java.

like image 26
jhn Avatar answered Nov 17 '22 19:11

jhn