×
☰ See All Chapters

Java Optional Class

Optional class has various utility methods to facilitate code to handle values as ‘available’ or ‘not available’ instead null checks. NullPointerException is hard to avoid and it may crash the application during run time. Too many null checks in the code make code less readable. The traditional way of checking the variable if null or not before doing operation is potential for bugs, as one could easily forget to perform the null checks in some part of the code if it is to check in many places. Java 8 has introduced Optional class to deal with nullable values explicitly and to follow best coding practices.  Optional class is introduced in java.util package. You must import java.util package to use this class.  Optional is a container and can store any object, which may be or may not be null. Optional objects are Final and immutable. If a value is present, isPresent() method will return true,  get() method will return the value, orElse() method will return a default value if value not present.

Creating Optional Objects

1. Create an non nullable Optional object(Optional.of(obj))

2. Create an nullable Optional object(Optional.ofNullable(obj))

3. Create an empty Optional object (Optional.empty())

package com.java4coding;

 

import java.util.Optional;

 

class Employee {

        public String getEmpNameInUppercase(String empName) {

                return empName.toUpperCase();

        }

}

 

public class Demo {

 

        public static void main(String args[]) {

 

                // Optional.ofNullable - allows passed parameter to be null.

                Optional<Employee> optional1 = Optional.ofNullable(new Employee());

                System.out.println(optional1.isPresent()); // true

               

                Optional<Employee> optional2 = Optional.ofNullable(null);

                System.out.println(optional2.isPresent()); // false

 

                // Optional.of - throws NullPointerException if passed parameter is null

                Optional<Employee> optional3 = Optional.of(new Employee());

                System.out.println(optional3.isPresent()); // true

               

                try {

                        Optional<Employee> optional4 = Optional.of(null); // java.lang.NullPointerException while storing

                } catch (Exception e) {

                        System.out.println("java.lang.NullPointerException");

                }

               

                Optional<Employee> optional5 = Optional.empty();

                System.out.println(optional5.isPresent()); // false

               

        }

}

ifPresent() instead of null check

package com.java4coding;

 

import java.util.Optional;

 

class Employee {

        public String getEmpNameInUppercase(String empName) {

                return empName.toUpperCase();

        }

}

 

public class Demo {

 

        public static void main(String args[]) {

 

                Employee e1 = new Employee();

               

                //Before Java 1.8

                if (e1 != null) {

                        System.out.println("if not null");

                }

               

                //Java 1.8

                if(Optional.ofNullable(e1).isPresent()) {

                        System.out.println("if not null");

                }

                //OR

                Optional.ofNullable(e1).ifPresent(name -> System.out.println("if not null"));

               

        }

}

Returning contained value-using get

package com.java4coding;

 

import java.util.Optional;

 

class Employee {

        public String getEmpNameInUppercase(String empName) {

                return empName.toUpperCase();

        }

}

 

public class Demo {

 

        public static void main(String args[]) {

 

                Optional<Employee> optional = Optional.ofNullable(new Employee());

               

                if (optional.isPresent()) {

                        System.out.println(optional.get().getEmpNameInUppercase("Manu Majunatha"));

                }

        }

}

 

Default Value if null by using orElse

The orElse(defaultVal) method is used to retrieve the value contained inside an Optional object. It takes one parameter which acts as a default value. With orElse(defaultVal)method, the contained value is returned if it is present and the default value given to orElse(defaultVal)method is returned if the contained value is absent.

package com.java4coding;

 

import java.util.Optional;

 

class Employee {

       

        String name;

        public Employee (String name) {

                this.name = name;

        }

        public String getEmpName() {

                return name;

        }

}

 

public class Demo {

 

        public static void main(String args[]) {

 

                Employee e1 = null;

                //orElse returns contained value if present otherwise returns default, e1 is null, it returns default value

           Employee e3 = Optional.ofNullable(e1).orElse( new Employee("Manu Manjunatha"));

           System.out.println(e3.getEmpName());

           

           

           Employee e4 = new Employee("Advith Tyagraj");

           //orElse returns contained value if present otherwise returns default, e4 is not null, it returns contained value       

           Employee e5 = Optional.ofNullable(e4).orElse( new Employee("Manu Manjunatha"));

           System.out.println(e5.getEmpName());

           

        }

}

Default function if null by using orElseGet

The orElseGet(Supplier<T>)method is also used to retrieve the value contained inside an Optional object. The orElseGet(Supplier<T>)method takes a supplier functional interface which is invoked if contained value is absent.

If we look into the Supplier<T> functional interface internal code, it is as given below:

@FunctionalInterface

public interface Supplier<T> {

 

    T get();

}

 

package com.java4coding;

 

import java.util.Optional;

 

class Employee {

       

        String name;

        public Employee (String name) {

                this.name = name;

        }

        public String getEmpName() {

                return name;

        }

}

 

public class Demo {

 

        public static void main(String args[]) {

 

                Employee e1 = null;

           //orElseGet takes a supplier functional interface which is executed if contained value is absent, e1 is null, it executes the functional interface

           Employee e3 = Optional.ofNullable(e1).orElseGet(() ->  new Employee("Manu Manjunatha"));

           System.out.println(e3.getEmpName());

           

           Employee e4 = new Employee("Advith Tyagraj");

           //orElseGet takes a supplier functional interface which is executed if contained value is absent, e4 is not null, it will not execute the functional interface

           Employee e5 = Optional.ofNullable(e4).orElseGet(() ->  new Employee("Manu Manjunatha"));

           System.out.println(e5.getEmpName());

           

        }

}

orElse vs orElseGet

orElse

orElseGet

orElse returns contained value if present otherwise returns default value, but even though it is returning contained object, default object will be created always. When it is returning contained object, there is no necessity of creating and keeping default object in memory. Suppose if we are using any database connection or any resource as default object then it is a serious memory issue while returning contained object.

orElseGet returns contained value if present otherwise executes functional interface. But here unlike orElse, functional interface code will not be executed and no objects are created while returning contained object.

Performance is not good as orElseGet

Performance is not good

Throw exception if null by using orElseThrow

package com.java4coding;

 

import java.util.Optional;

 

class Employee {

       

        String name;

        public Employee (String name) {

                this.name = name;

        }

        public String getEmpName() {

                return name;

        }

}

 

public class Demo {

 

        public static void main(String args[]) {

 

                Employee e1 = null;

               

                //Return the contained value, if present, otherwise throw an exception by executing provided functional interface. e1 is null, throws IllegalArgumentException.

                try {

                        Employee e2 = Optional.ofNullable(e1).orElseThrow(() ->  new IllegalArgumentException());

                } catch (IllegalArgumentException e) {

                        System.out.println("Exception is thrown");

                }

         

           

           Employee e3 = new Employee("Manu Manjunatha");

           

           //Return the contained value, if present, otherwise throw an exception by executing provided functional interface. e3 is not null, returns e3.           

                try {

                        Employee e4 = Optional.ofNullable(e3).orElseThrow(() ->  new IllegalArgumentException());

                } catch (IllegalArgumentException e) {

                        System.out.println("Exception is thrown");

                }

        }

}

Filtering the contained value using filter

The filter(Predicate<T> predicate) is used to filter the contained value. This method takes a Predicate as an argument and returns an Optional object. If the contained value passes testing by the predicate, then the Optional is returned as is. However, if the predicate returns false, then an empty Optional is returned.

Note: If contained value passes testing by the predicate then here same Optional object is returned and not the contained value.

Predicate is a functional interface and its internal code is as given below:

@FunctionalInterface

public interface Predicate<T> {

 

    boolean test(T t);

… …

… …

}

 

package com.java4coding;

 

import java.util.Optional;

 

public class Demo {

 

        public static void main(String args[]) {

 

                Optional<Integer> optional1 = Optional.ofNullable(new Integer(5));

 

                Optional<Integer> optional2 = optional1.filter(x -> x < 10);

                System.out.println(optional2.isPresent());

               

                Optional<Integer> optional3 = optional1.filter(x -> x > 10);

                System.out.println(optional3.isPresent());

               

        }

}

Transforming the contained value using map

Using map(Function<T, R> function) we can transform the optional object. We can transform the optional object into completely a new related form. A list optional object can be transformed to an integer optional object, but here integer should be derived from list only, say it can be size value of the list. When we transform one optional object to another, then those should be somewhat related. Taking one optional object we cannot return a completely new optional object.

map method takes the object of Functional Interface Function, whose internal code is as given below:

@FunctionalInterface

public interface Function<T, R> {

 

    R apply(T t);

… …

… …

}

 

package com.java4coding;

 

import java.util.Arrays;

import java.util.List;

import java.util.Optional;

 

public class Demo {

 

        public static void main(String args[]) {

 

                Optional<String> optinal = Optional.of("manu mnajunatha");

                System.out.println(optinal);//Prints Optional[manu mnajunatha]

 

                Optional<String> modifiedOptinal = optinal.map(x->x.toUpperCase());

                System.out.println(modifiedOptinal);//Prints Optional[MANU MNAJUNATHA]

               

                Optional<List<String>> listOptional = Optional.of(Arrays.asList("Manu", "Advith", "Tyagraj", "Likitha"));

                System.out.println(listOptional.map(x -> x.size()));//Prints Optional[4]

        }

}

 

Transforming the contained optional value using flatMap

Using map we have transformed the contained value and returned the Optional object. However, suppose if contained value is another Optional object, using map we can transform the value contained in Optional of Optional object. Finally, we can return Optional of Optional object.

Using flatmap() we can transform the value contained in Optional of Optional object and we can just return Optional object.

Also while transforming the value, we may encounter the possibility of null value, using map we cannot apply Optional.of() or Optional.ofNullable() to value. But Using flatmap() we can apply Optional.of() or Optional.ofNullable() to ensure null check, but even after using Optional.of() or Optional.ofNullable() still we can return Optional object and not Optional of Optional object.

package com.java4coding;

 

import java.util.Optional;

 

public class Demo {

 

        public static void main(String args[]) {

 

                Optional<String> optinal = Optional.of("manu mnajunatha");

                System.out.println(optinal);//Prints Optional[manu mnajunatha]

 

                Optional<String> modifiedOptinal = optinal.map(x->x.toUpperCase());

                //Optional<String> modifiedOptinal = optinal.map(x->Optional.of(x.toUpperCase())); //This is not possible, but possible with flatMap and still we can return Optional<String>

                //So while transforming the value we cannot ensure the null check.

                System.out.println(modifiedOptinal);//Prints Optional[MANU MNAJUNATHA]

               

                Optional<String> modifiedOptinal2 = optinal.flatMap(x->Optional.of(x.toUpperCase()));

                System.out.println(modifiedOptinal2);//Prints Optional[MANU MNAJUNATHA]

               

               

                Optional<Optional> optinal2 = Optional.of(Optional.of("manu mnajunatha"));

                System.out.println(optinal2);//Optional[Optional[manu mnajunatha]]

 

                Optional<Optional<String>> modifiedOptinal3 = optinal2.map(x->x.map(y->((String) y).toUpperCase()));

                System.out.println(modifiedOptinal3);//Prints Optional[Optional[MANU MNAJUNATHA]]

               

                Optional<Optional<String>> modifiedOptinal4 = optinal2.flatMap(x->x.map(y->((String) y).toUpperCase()));

                System.out.println(modifiedOptinal4);//Prints Optional[MANU MNAJUNATHA]

               

        }

}

 


All Chapters
Author