Site Search:

Develop code that uses the Optional class

Back>

Before java 8, we use if(xxx != null && xxx.xxx != null) to prevent NullPointerException.

Optional type is introduced in java 8, as a better weapon to fight NullPointerException.

Optional<T>
Optional<T>

Java doc is one of the best text book for studying java, as it is the definition document. Here is the relevant part for OCPJP:

public final class Optional<T>
extends Object
A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.Additional methods that depend on the presence or absence of a contained value are provided, such as orElse() (return a default value if value not present) and ifPresent() (execute a block of code if the value is present).
This is a value-based class; use of identity-sensitive operations (including reference equality (==), identity hash code, or synchronization) on instances of Optional may have unpredictable results and should be avoided.

Modifier and TypeMethod and Description
static <T> Optional<T>empty()
Returns an empty Optional instance.


Optional<T>filter(Predicate<? super T> predicate)
If a value is present, and the value matches the given predicate, return an Optional describing the value, otherwise return an empty Optional.
<U> Optional<U>flatMap(Function<? super T,Optional<U>> mapper)
If a value is present, apply the provided Optional-bearing mapping function to it, return that result, otherwise return an empty Optional.
Tget()
If a value is present in this Optional, returns the value, otherwise throws NoSuchElementException.


voidifPresent(Consumer<? super T> consumer)
If a value is present, invoke the specified consumer with the value, otherwise do nothing.
booleanisPresent()
Return true if there is a value present, otherwise false.
<U> Optional<U>map(Function<? super T,? extends U> mapper)
If a value is present, apply the provided mapping function to it, and if the result is non-null, return an Optional describing the result.
static <T> Optional<T>of(T value)
Returns an Optional with the specified present non-null value.
static <T> Optional<T>ofNullable(T value)
Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional.
TorElse(T other)
Return the value if present, otherwise return other.
TorElseGet(Supplier<? extends T> other)
Return the value if present, otherwise invoke other and return the result of that invocation.
<X extends Throwable>
T
orElseThrow(Supplier<? extends X> exceptionSupplier)
Return the contained value, if present, otherwise throw an exception to be created by the provided supplier.
StringtoString()
Returns a non-empty string representation of this Optional suitable for debugging.

Common Usage


As the following example shows the common usage.
The Optional<T> can be created with factory method Optional.Empty(), Optional.of() and Optional.ofNullable().

OCPJP>cat OptionalDemo.java 
import java.util.Optional;
public class OptionalDemo {
    public static void main(String... args) {
        Optional<String> op = Optional.empty();
        Optional<String> op2 = Optional.of("Optional.of() created");
        
        try {
            testOptional(op2);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        try {
            testOptional(op);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        
        String value = null;
        Optional<String> op3 = Optional.ofNullable(value);
        try {
            testOptional(op3);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        
        Optional<String> op4 = Optional.ofNullable("Optional.ofNullable() created");
        try {
            testOptional(op4);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }      
        
        System.out.println("===============get Empty throws NoSuchElementException");
        op.get();
    }
    
    private static <T>void testOptional(Optional<T> op) throws Exception {
        System.out.println("====================" + op);
        //value path
        if(op.isPresent()) {
            System.out.println("Optional.get() returns value or throw exception: " + op.get());
        }
        op.ifPresent(i -> System.out.println("from Optional.ifPresent(): " + op.get()));
        
        //value and null path
        System.out.println(op.orElse((T)"default value set by Optinal.orElse(T)"));
        System.out.println(op.orElseGet(() -> (T)"default value set by Optional.orElseGet()"));
        op.orElseThrow(() -> new NullPointerException("oldy goody NullpointerException"));
    }
}
OCPJP>javac OptionalDemo.java 
Note: OptionalDemo.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
OCPJP>java OptionalDemo
====================Optional[Optional.of() created]
Optional.get() returns value or throw exception: Optional.of() created
from Optional.ifPresent(): Optional.of() created
Optional.of() created
Optional.of() created
====================Optional.empty
default value set by Optinal.orElse(T)
default value set by Optional.orElseGet()
oldy goody NullpointerException
====================Optional.empty
default value set by Optinal.orElse(T)
default value set by Optional.orElseGet()
oldy goody NullpointerException
====================Optional[Optional.ofNullable() created]
Optional.get() returns value or throw exception: Optional.ofNullable() created
from Optional.ifPresent(): Optional.ofNullable() created
Optional.ofNullable() created
Optional.ofNullable() created
===============get Empty throws NoSuchElementException
Exception in thread "main" java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:135)
at OptionalDemo.main(OptionalDemo.java:34)
OCPJP>


Primitive Optional

We have studied primitive streams, Optional<T> also have primitive versions OptionalDouble, OptionalInt, OptionalLong.

OptionalDouble

OCPJP>cat OptionalDoubleDemo.java 
import java.util.OptionalDouble;
public class OptionalDoubleDemo {
    public static void main(String[] args) {
        OptionalDouble optionalDouble = OptionalDouble.empty();
        try {
            testOptionalDouble(optionalDouble);
        } catch(Exception e) {
            System.out.println(e.getMessage());
        }
        
        optionalDouble = OptionalDouble.of(3.1415);
        testOptionalDouble(optionalDouble);
        
        OptionalDouble.empty().getAsDouble();
        
    }
    
    public static void testOptionalDouble(OptionalDouble optionalDouble) {
        System.out.println("=====================" + optionalDouble);
        
        if(optionalDouble.isPresent()) {
            System.out.println(optionalDouble.getAsDouble());
        }
        
        optionalDouble.ifPresent(d -> System.out.println("from OptionalDouble.ifpresent(): " + d));
        
        System.out.println("from OptionalDouble.orElse: " + optionalDouble.orElse(Double.NaN));
        System.out.println(optionalDouble.orElseGet(Math::random));
        optionalDouble.orElseThrow(() -> new NullPointerException("oldy goody NullPointerException"));
    }
}
OCPJP>javac OptionalDoubleDemo.java 
OCPJP>java OptionalDoubleDemo
=====================OptionalDouble.empty
from OptionalDouble.orElse: NaN
0.05453735961349904
oldy goody NullPointerException
=====================OptionalDouble[3.1415]
3.1415
from OptionalDouble.ifpresent(): 3.1415
from OptionalDouble.orElse: 3.1415
3.1415
Exception in thread "main" java.util.NoSuchElementException: No value present
at java.util.OptionalDouble.getAsDouble(OptionalDouble.java:118)
at OptionalDoubleDemo.main(OptionalDoubleDemo.java:14)

OCPJP>


OptionalInt

OCPJP>cat OptionalIntDemo.java 
import java.util.OptionalInt;
public class OptionalIntDemo {
    public static void main(String... args) {
        OptionalInt optionalInt = OptionalInt.empty();
        try {
            testOptionalInt(optionalInt);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        optionalInt = OptionalInt.of(3);
        testOptionalInt(optionalInt);
    }
    
    public static void testOptionalInt(OptionalInt optionalInt) {
        System.out.println("====================" + optionalInt);
        if(optionalInt.isPresent()) {
            System.out.println(optionalInt.getAsInt());
        }
        optionalInt.ifPresent(i -> System.out.println("from OptionalInt.ifPresent: " + optionalInt.getAsInt()));
        
        System.out.println("from OptionalInt.orElse: " + optionalInt.orElse(3));
        System.out.println("from OptionalInt.orElseGet: " + optionalInt.orElseGet(() -> 3));
        optionalInt.orElseThrow(() -> new NullPointerException("oldy goody NullPointerException"));
    }
}

OCPJP>
OCPJP>
OCPJP>javac OptionalIntDemo.java 
OCPJP>java OptionalIntDemo
====================OptionalInt.empty
from OptionalInt.orElse: 3
from OptionalInt.orElseGet: 3
oldy goody NullPointerException
====================OptionalInt[3]
3
from OptionalInt.ifPresent: 3
from OptionalInt.orElse: 3
from OptionalInt.orElseGet: 3

OCPJP>


OptionalLong
OCPJP>cat OptionalLongDemo.java 
import java.util.OptionalLong;
public class OptionalLongDemo {
    public static void main(String... args) {
        OptionalLong optionalLong = OptionalLong.empty();
        try{
            testOptionalLong(optionalLong);
        } catch(Exception e) {
            System.out.println(e.getMessage());
        }
        
        optionalLong = OptionalLong.of(3L);
        testOptionalLong(optionalLong);
    }
    
    private static void testOptionalLong(OptionalLong optionalLong) {
        System.out.println("===============" + optionalLong);
        if(optionalLong.isPresent()) {
            System.out.println("from OptionalLong.getAsLong: " + optionalLong.getAsLong());
        }
        optionalLong.ifPresent(l -> System.out.println("form OptionalLong.ifPresent: " + optionalLong.getAsLong()));
        
        System.out.println("from OptionalLong.orElse: " + optionalLong.orElse(3L));
        
        System.out.println("from OptionalLong.orElseGet: " + optionalLong.orElseGet(() -> 3L));
        
        optionalLong.orElseThrow(() -> new NullPointerException("oldy goody NullPointerException"));
        
    }
}
OCPJP>
OCPJP>
OCPJP>javac OptionalLongDemo.java 
OCPJP>java OptionalLongDemo
===============OptionalLong.empty
from OptionalLong.orElse: 3
from OptionalLong.orElseGet: 3
oldy goody NullPointerException
===============OptionalLong[3]
from OptionalLong.getAsLong: 3
form OptionalLong.ifPresent: 3
from OptionalLong.orElse: 3
from OptionalLong.orElseGet: 3

OCPJP>



Optional Chaining

Optionals can be chained like streams. It has two intermediate operations, filter and map

OCPJP>cat ChainingOptionalDemo.java 
import java.util.Optional;
public class ChainingOptionalDemo {
    public static void main(String...args) {
        System.out.println("Optional<T> have intermediate operations like stream does");
        Optional<String> optional = Optional.empty();
        System.out.println("an empty Optional will skip all intermidiate operations");
        optional.map(String::toUpperCase).filter(i -> i.length() > 3)
        .ifPresent(System.out::println);
        
        System.out.println("if an Optional get filtered out, the rest of the intermidiate steps are skipped");
        optional = Optional.of("cat");
        try {
            optional.filter(i -> i.equals("dog")).map(String::toUpperCase).get();
        } catch(Exception e) {
            System.out.println(e.getMessage());
        }
        
        optional.map(String::toUpperCase).filter(i -> i.length() < 5).ifPresent(System.out::println);
        
        String orElse = optional.filter(i -> i.length() > 5).map(String::toLowerCase)
                .orElse("didn't pass filter, skip to orElse");
        System.out.println(orElse);
        
        System.out.println("OptionalDouble, OptionalInt, OptionalLong don't have filter and map methods");
    }
}
OCPJP>
OCPJP>
OCPJP>
OCPJP>
OCPJP>javac ChainingOptionalDemo.java 
OCPJP>java ChainingOptionalDemo
Optional<T> have intermediate operations like stream does
an empty Optional will skip all intermidiate operations
if an Optional get filtered out, the rest of the intermidiate steps are skipped
No value present
CAT
didn't pass filter, skip to orElse
OptionalDouble, OptionalInt, OptionalLong don't have filter and map methods

OCPJP>


Some stream terminal operations return Optional and primitive Optional.
For example IntStream.average, IntStream.max, Stream<T>.findFirst, DoubleStream.findAny.

OCPJP>cat StreamOptionalDemo.java 
import java.util.stream.*;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;

public class StreamOptionalDemo {
    public static void main(String[] args) {
        IntStream intStream = IntStream.range(1, 6);
        DoubleStream doubleStream = DoubleStream.of(0.1, 0.3, 0.5, 0.7);
        LongStream longStream = LongStream.range(1L, 6L);
        
        OptionalDouble optionalDouble = intStream.average();
        optionalDouble.ifPresent(d -> System.out.println("IntStream.average.getAsDouble: " + optionalDouble.getAsDouble()));
        
        OptionalDouble optionalDouble2 = doubleStream.average();
        optionalDouble2.ifPresent(d -> System.out.println("DoubleStream.average.getAsDouble: " + optionalDouble2.getAsDouble()));
        
        OptionalDouble optionalDouble3 = longStream.average();
        optionalDouble3.ifPresent(d -> System.out.println("LongStream.average.getAsDouble: " + optionalDouble3.getAsDouble()));
        
        OptionalInt optionalInt = IntStream.range(1, 6).min();
        System.out.println("IntStream.min.orElse: " + optionalInt.orElse(0));
        optionalInt = IntStream.rangeClosed(1, 6).max();
        if(optionalInt.isPresent()) {
            System.out.println("IntStream.max.getAsInt: " + optionalInt.getAsInt());
        }
        
        Optional<String> optional = Stream.generate(() -> "something").findAny();
        System.out.println("Stream<String>.findAny.get: " + optional.get());
        optional = Stream.generate(() -> "something else").findFirst();
        System.out.println("Stream<String>.findFirst.get: " + optional.get());
        
        optionalInt = IntStream.generate(() -> 10).findAny();
        System.out.println("IntStream.findAny.orElseGet: " + optionalInt.orElseGet(() -> 0));
        
        optionalInt = IntStream.iterate(0, i -> i + 1).findFirst();
        System.out.println("IntStream.findFirst.orElseThrow: " + optionalInt.orElseThrow(() -> new NullPointerException()));
    }
}
OCPJP>
OCPJP>
OCPJP>javac StreamOptionalDemo.java 
OCPJP>java StreamOptionalDemo
IntStream.average.getAsDouble: 3.0
DoubleStream.average.getAsDouble: 0.39999999999999997
LongStream.average.getAsDouble: 3.0
IntStream.min.orElse: 1
IntStream.max.getAsInt: 6
Stream<String>.findAny.get: something
Stream<String>.findFirst.get: something else
IntStream.findAny.orElseGet: 10
IntStream.findFirst.orElseThrow: 0
OCPJP>



We have almost covered everything OCJPJ requires, the rest of the Optional usage will be mentioned in other stream related topics.