Pages

Sunday 22 September 2019

Optional

Q.What is the alternative to null in Java?
Java 8 introduces a new class called java.util.Optional<T> that’s inspired by the ideas of Haskell and Scala. It’s a class that encapsulates an optional value.


Q.How do you model the absence of a value?
Imagine you have the following nested object structure for a person owning a car and having car insurance.
The Person / Car / Insurance data model
If you design your classes like below
  1. class Person{
  2.     private Car car;
  3.     public Car getCar() {
  4.         return car;
  5.     }
  6. }
  1. class Car{
  2.     private Insurance insurance;
  3.     public Insurance getInsurance() {
  4.         return insurance;
  5.     }
  6. }
  1. class Insurance {
  2.     private String name;
  3.     public String getName() {
  4.         return name;
  5.     }
  6. }
  1. class Test {
  2.     public String getCarInsuranceName(Person person) {
  3.         return person.getCar().getInsurance().getName();
  4.     }
  5. public static void main(String[] args) {
  6.     Test t = new Test();
  7.     t.getCarInsuranceName(new Person());
  8. }
Problems with null
  • It’s a source of error. NullPointerException is by far the most common exception in Java.
  • It bloats your code. It worsens readability by making it necessary to fill your code with often deeply nested null checks.
  • It’s meaningless. It doesn’t have any semantic meaning, and in particular, it represents the wrong way to model the absence of a value in a statically typed language.
  • It breaks Java philosophy. Java always hides pointers from developers except in one case: the null pointer.
  • It creates a hole in the type system. null carries no type or other information, meaning it can be assigned to any reference type. This is a problem because, when it’s propagated to another part of the system, you have no idea what that null was initially supposed to be.

I argue that using null to represent the absence of a value is the wrong approach.
What you need is a better way to model the absence and presence of a value.

Redefining the Person / Car / Insurance data model using Optional
  1. class Person {
  2.     private Optional<Car> car;
  3.     public Optional<Car> getCar() {
  4.         return car;
  5.     }
  6. }
  1. class Car {
  2.     private Optional<Insurance> insurance;
  3.     public Optional<Insurance> getInsurance() {
  4.         return insurance;
  5.     }
  6. }
  1. class Insurance {
  2.     private String name;
  3.     public String getName() {
  4.         return name;
  5.     }
  6. }
  1. class OptionalVersion {
  2. public String getCarInsurance(Optional<Person1> person) {
  3.     return person.flatMap(Person1::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("Unknow");
  4. }
  5.     public static void main(String[] args) {
  6.         OptionalVersion t = new OptionalVersion();
  7.         Optional<Person> p = Optional.empty();
  8.         System.out.println(t.getCarInsurance(p));;
  9.     }

  10. }

Creating Optional objects
There are several ways to create  Optional objects.
Empty optional:
Optional<Car> optCar = Optional.empty();
Optional from a non-null value:
Optional<Car> optCar = Optional.of(car);
If car were null, a NullPointerException would be immediately thrown (rather than getting a
latent error once you try to access properties of the car).
Optional from null:
Optional<Car> optCar = Optional.ofNullable(car);
If car were null, the resulting Optional object would be empty

The methods of the Optional class

Method Description
empty Returns an empty Optional instance
filter If the value is present and matches the given predicate, returns this Optional; otherwise
returns the empty one
flatMap If a value is present, returns the Optional resulting from the application of the provided
mapping function to it; otherwise returns the empty Optional
get Returns the value wrapped by this Optional if present, otherwise throws a NoSuchElementException
ifPresent If a value is present, invokes the specified consumer with the value; otherwise does nothing
isPresent Returns true if there is a value present; otherwise false
map If a value is present, applies the provided mapping function to it
of Returns an Optional wrapping the given value or throws a NullPointerException if this value
is null
ofNullable Returns an Optional wrapping the given value or the empty Optional if this value is null
orElse Returns the value if present or the given default value otherwise
orElseGet Returns the value if present or the one provided by the given Supplier otherwise
orElseThrow Returns the value if present or throws the exception created by the given Supplier otherwise