Optional Class in Java 8

Optional Class in Java 8

Optional is a generic class defined in the java.util package, that got introduced in Java 8.

It facilitates the handling of potentially absent values in a more concise and expressive manner.
It provides a container-like structure to wrap objects, indicating the possibility of a value being present or absent.

Its primary purpose is to provide a safer alternative to handling null values, thereby reducing the risk of NullPointerException. By explicitly acknowledging the possibility of an absent value, Optional encourages developers to write more robust and error-resistant code.

Without Optional (custom null check):

public String getStudentName() {
  // can be null or non-null value
  Student student = fetchStudent(); 
  if(student != null){
    return student.getName();
  }else {
    return null;
  }
}

With Optional:

public Optional<String> getStudentName() {
  // can be null or non-null value
  Optional<Student> student = Optional.ofNullable(fetchStudent()); 
  if(student.isPresent()){
    return Optional.of(student.getName());
  }
  return Optional.empty();
}

Creating Optional Instances


To create an Optional instance, the following methods are provided:

  1. Optional.of(T value):

    • Creates an Optional object containing a non-null value.

    • Throws: NullPointerException if the value provided is null.

    • Example:

        String name = "John Doe";
        Optional<String> optionalName = Optional.of(name);
        System.out.println("Optional Name: " + optionalName);
      

      Output:

        Optional Name: Optional[John Doe]
      
  2. Optional.ofNullable(T value):

    • Creates an Optional object containing the specified value.

    • The value can be null, in that case, the Optional will be empty.

    • Example:

        String city = null;
        Optional<String> optionalCity = Optional.ofNullable(city);
        System.out.println("Optional City: " + optionalCity);
      

      Output:

        Optional City: Optional.empty
      
  3. Optional.empty():

    • Creates an empty Optional object with no value/null value.

    • Example:

        Optional<String> optionalEmail = Optional.empty();
        System.out.println("Empty Optional Email: " + optionalEmail);
      

      Output:

        Empty Optional Email: Optional.empty
      

Methods and Usage:


Using the Optional instance, the following methods can be utilized to manipulate and retrieve values.

  1. boolean isPresent():

    • Returns true if the Optional contains a non-null value, otherwise returns false.

    • Example:

        Optional<String> optionalName = Optional.of("John Doe");
        if (optionalName.isPresent()) {
           System.out.println("Name: " + optionalName.get());
        } else {
           System.out.println("No name found.");
        }
      

      Output:

        Name: John Doe
      
  2. T get():

    • Returns the value wrapped by the Optional if present.

    • Throws: NoSuchElementException if the Optional is empty.

    • Example:

        Optional<String> optionalName = Optional.of("John Doe");
        String name = optionalName.get();
        System.out.println("Name: " + name);
      

      Output:

        Name: John Doe
      
  3. T orElse(T defaultValue):

    • Returns the value wrapped by the Optional if present.

    • Returns: defaultValue if the Optional is empty.

    • Example:

        Optional<String> optionalCity = Optional.empty();
        String city = optionalCity.orElse("Unknown City");
        System.out.println("City: " + city);
      

      Output:

        City: Unknown City
      
  4. T orElseGet(Supplier<? extends T> supplier):

    • Returns the value wrapped by the Optional if present.

    • Invokes the supplier function to provide an alternative value if the Optional is empty.

    • Example:

        Optional<String> optionalEmail = Optional.empty();
        String email = optionalEmail.orElseGet(() -> "abc@def.com");
        System.out.println("Email: " + email);
      

      Output:

        Email: abc@def.com
      
  5. T orElseThrow(Supplier<? extends X> exceptionSupplier):

    • Returns the value wrapped by the Optional if present.

    • Throws an exception produced by the exceptionSupplier if the Optional is empty.

    • Example:

        Optional<String> optionalName = Optional.empty();
        String name = optionalName.orElseThrow(() -> new IllegalArgumentException("Name is absent"));
      

      Output:

        Exception in thread "main" java.lang.IllegalArgumentException: Name is absent
        .....
        .....
      
  6. void ifPresent(Consumer<? super T> consumer):

  • Executes the specified consumer function with the value wrapped by the Optional if present.

  • Example:

      Optional<String> optionalPhone = Optional.of("123456789");
      optionalPhone.ifPresent(phone -> System.out.println("Phone: " + phone));
    

    Output:

      Phone: 123456789
    

Note:
when the value wrapped by an Optional is null, it is equivalent to using Optional.empty(). Both represent an empty Optional object with no value.

For example:

String value = null;

Optional<String> optional1 = Optional.ofNullable(value);
Optional<String> optional2 = Optional.empty();

System.out.println(optional1.equals(optional2)); //true

Both Optional.empty() and Optional.ofNullable(null) are commonly used to handle cases where a value might be absent or null.

Conclusion:

Optional in Java is a valuable tool for handling potentially absent values without relying on null references and null checks.