Wednesday, October 13, 2021

Introduction to the Optional API

 I used the  Optional class for a library I am writing. There are not many good introductions to it so I thought of writing something here.


We may view the optional as a container that might have something in it (a value) or it might be empty. This comes in handy if you are expecting a null or empty value

public class DoubleIt {

       public static Optional<Integer> twice(Integer score){

             if (score==null) return Optional.empty();

             return Optional.of(score*2);

       }

       public static void main(String[] args) {

             out.println(twice(100));

             out.println(twice(null));

}

}

// output : “Optional[200]

// output : “Optional.empty

 

Normally we want to check if the value is there or not. This is how we will likely check:

             // retrieve value

             Optional<Integer> a= twice(100);

             if (a.isPresent()) out.println("Double straight : " + a.get());

             // if calling .get on empty then we get an error java.util.NoSuchElementException

// output: Double straight : 200

So now that we know how to retrieve a value we see that there may be a pattern emerging. We may write the same method twice as in above in a single line so:

import java.util.Optional;

import java.util.function.Supplier;

import static java.lang.System.out;

public class DoubleIt {

       public static Optional<Integer> twiceBrief(Integer score){// using ternary operator

             Optional o = (score==null)?  Optional.empty():  Optional.of(score*2);

             return o;

       }

       public static void main(String[] args) {

             // brief

             Optional<Integer> abrf= twiceBrief(100);

             if (abrf.isPresent()) out.println("Double with ternary operator : " + abrf.get());

// output: Double with ternary operator : 200

       }

}

Since the above is a pattern there is a provided method for dealing with the above scenario.

import java.util.Optional;

import java.util.function.Supplier;

import static java.lang.System.out;

public class DoubleIt {

       public static Optional<Integer> twiceBriefer(Integer score){

             return Optional.ofNullable(score*2); // same as twiceBrief and twice

       }

       public static void main(String[] args) {

             //briefer

             Optional<Integer> abrfr= twiceBriefer(100);

             if (abrfr.isPresent()) out.println("Double using ofNullable : "+abrfr.get());

             // output: Double using ofNullable : 200

       }

}

Following are some of the methods that may be helpful in the Optional class API.

ifPresent

void

ifPresent(Consumer<? super T> consumer)

If a value is present, invoke the specified consumer with the value, otherwise do nothing.

Now using ifPresent:

public class DoubleIt {

       public static Optional<Integer> twice(Integer score){

             if (score==null) return Optional.empty();

             return Optional.of(score*2);

       }

       public static void main(String[] args) {

             // using ifPresent

             Optional<Integer> aalt = twice(500);

             // in the following a consumer consumes a value

             aalt.ifPresent(out::println);

// out::println is same as : str -> System.out.println(str)
       // output:
1000

}

}

orElse

T

orElse(T other)

Return the value if present, otherwise return other.

What if a value is not present:

public class DoubleIt {

       public static Optional<Integer> twice(Integer score){

             if (score==null) return Optional.empty();

             return Optional.of(score*2);

       }

       public static void main(String[] args) {

             // what if a value is NOT present

             Optional<Integer> ae= twice(null);

             out.println("When empty return 0 : "+ae.orElse(0));
            
// output : When empty return 0 : 0

}

}

orElseGet

T

orElseGet(Supplier<? extends T> other)

Return the value if present, otherwise invoke other and return the result of that invocation.

Following allows you to invoke a supplier method & return the result.

public class DoubleIt {

       public static Optional<Integer> twice(Integer score){

             if (score==null) return Optional.empty();

             return Optional.of(score*2);

       }

       public static void main(String[] args) {

out.println("When empty return some random calculation : "

+ae.orElseGet( () -> (  (int)( Math.random() * 1000)  )   )  

);

// with further elaboration on the supplier function

out.println("When empty return some random calculation too : "

+ae.orElseGet( () -> {

                                        out.println("Inside the supplier lambda function"); 

                                        return (int)( Math.random() * 1000)  ;  

                                         }  

                                  )

                    ) ;

}

}

You may refactor out the supplier method so:

import java.util.Optional;

import java.util.function.Supplier;

import static java.lang.System.out;

public class DoubleIt {

      

       public static void main(String[] args) {

             // separate supplier method refactored out

             Supplier<Integer> m = () ->{

                    out.println("Inside the separately defined supplier lambda function"); 

                    return (int)( Math.random() * 1000)  ;  

             };

             out.println("When empty return some random calculation : "+ae.orElseGet(m) ) ;

       }

}

 

Or you may have the supplier method at class level instead of at method level:

import java.util.Optional;

import java.util.function.Supplier;

import static java.lang.System.out;

public class DoubleIt {  

       public static void main(String[] args) {

             //

             out.println("When empty return some random calculation : "

+ae.orElseGet(DoubleIt::r ) ) ; 

       }

      

       public static Integer r() {

             out.println("Inside the separately defined static supplier method ");  

             return (int)( Math.random() * 1000)  ;

       }

}

No comments:

Total Pageviews

Popular Posts