Home > Enterprise >  How to Write a Change Detector with Two Optionals in Functional Java?
How to Write a Change Detector with Two Optionals in Functional Java?

Time:03-30

Is there a functional way to write a change reporter for two optional variables? The code is meant to detect value changes when moving from the value in Optional A to the value in Optional B with one quirk, that if Optional B is empty then we report a default value.

I want the following behavior:

 ------------ ------------ --------- 
| Optional A | Optional B | Result  |
 ------------ ------------ --------- 
| empty      | empty      | empty   |
| empty      | y          | y       |
| x          | empty      | default |
| x          | y          | y       |
| x          | x          | empty   |
 ------------ ------------ --------- 

I have a solution that looks like It should be simpler:

public Optional<String> reportChange(Optional<String> aOpt, Optional<String> bOpt) {
   if(aOpt.isPresent() && bOpt.isEmpty()) {
       return Optional.of(DEFAULT_VALUE);
   } else if (bOpt.isEmpty()){
       return Optional.empty();
   }
   return bOpt.flatMap(b -> {
       if (aOpt.isEmpty() || b.compareToIgnoreCase(aOpt.orElseThrow()) != 0) {
           return Optional.of(b);
       }
       return Optional.empty();
   });
}

What is the functional-programming way to write this?

CodePudding user response:

Your code can be simplified to a simple conditional expression:

public Optional<String> reportChange(Optional<String> aOpt, Optional<String> bOpt) {
    return aOpt.equals(bOpt)
       ? Optional.empty()
       : Optional.of(bOpt.orElse(DEFAULT_VALUE));
}

CodePudding user response:

Although such Optional usage isn't a good practice, this method does what required.

As I understood your logic x is an undesired value, that can be present in the optional A. If optional B has is present and has the same value the result should be an empty optional (the last row in the table).

The condition eliminates this case. Otherwise, when optional B is present, it will be returned as a result.

If optional B is empty, then based on the presence of optional A, the result will be either an empty optional or Optional.of(DEFAULT_VALUE).

public Optional<String> reportChange(Optional<String> a, Optional<String> b) {

    return a.isPresent() && b.isPresent() && a.get().equalsIgnoreCase(b.get()) ?
            Optional.empty() : 
            b.or(() -> a.isPresent() ? Optional.of(DEFAULT_VALUE) : Optional.empty());
}

Important note:

  • Optional type is meant to be used only as return type. That was the only intention of the designers of Java when optional was introduced in the JDK. Usage of optional as a parameter is discouraged. The better option from the perspective of clean code is to unpack both optionals right "on the spot" (in the code that obtains these values), and then apply conditional logic.
  • Related