Slide 1

Slide 1 text

Optional Say no to NullPointerExceptions! @ordepdev

Slide 2

Slide 2 text

The billion dollar mistake Null references have historically been a bad idea

Slide 3

Slide 3 text

Problems with null It’s meaningless. It bloats your code. It’s a source of error. It breaks Java philosophy. It creates a hole in the type system.

Slide 4

Slide 4 text

Before Optional public class Person { private Car car; public Car getCar() { return car; } public class Car { private Insurance insurance; public Insurance getInsurance() { return insurance; } } public class Insurance { private String name; public String getName() { return name; } } }

Slide 5

Slide 5 text

Before Optional public String getCarInsuranceName(Person person) { if (person != null) { Car car = person.getCar(); if (car != null) { Insurance insurance = car.getInsurance(); if (insurance != null) { return insurance.getName(); } } } return "Unknown"; }

Slide 6

Slide 6 text

Better alternative? person?.car?.insurance?.name Safe navigation operator from languages like Groovy, C#, and Kotlin Maybe a = Nothing | Just a Types that encapsulates an optional value from languages like Haskell and Scala Option[A] = if (x == null) None else Some(x)

Slide 7

Slide 7 text

Optional T Optional Optional Is empty Contains a non-null reference to a given T

Slide 8

Slide 8 text

IT’S A MONAD! filter(), map(), flatMap(), orElse()

Slide 9

Slide 9 text

WELL… ALMOST! Optional car = null;

Slide 10

Slide 10 text

FROM NULL TO Optional public class Person { private Car car; public Optional getCar() { return Optional.ofNullable(car); } public class Car { private Insurance insurance; public Optional getInsurance() { return Optional.ofNullable(insurance); } } public class Insurance { private String name; public String getName() { return name; } } }

Slide 11

Slide 11 text

FROM NULL TO Optional public String getCarInsuranceName(Person person) { return Optional.ofNullable(person) .flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("Unknown"); }

Slide 12

Slide 12 text

FROM NULL TO Optional public String getCarInsuranceName(Person person) { return Optional.ofNullable(person) .flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("Unknown"); }

Slide 13

Slide 13 text

FROM NULL TO Optional public String getCarInsuranceName(Person person) { return Optional.ofNullable(person) .flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("Unknown"); }

Slide 14

Slide 14 text

FROM NULL TO Optional public String getCarInsuranceName(Person person) { return Optional.ofNullable(person) .flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("Unknown"); }

Slide 15

Slide 15 text

FROM NULL TO Optional public String getCarInsuranceName(Person person) { return Optional.ofNullable(person) .flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("Unknown"); }

Slide 16

Slide 16 text

OR EVEN IF IT’S REQUIRED… public String getCarInsuranceName(Person person) { return Optional.ofNullable(person) .flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElseThrow(() -> new RuntimeException( “Insurance not available.” ); }

Slide 17

Slide 17 text

CODE SMELLS Don’t try this at home

Slide 18

Slide 18 text

METHOD CHAINING IS COOL, BUT… AVOIDING IF-STATEMENTS Optional.ofNullable(person) .ifPresent(this::doSomeWork); if (person != null) { this.doSomeWork(); } just stay with…

Slide 19

Slide 19 text

Optional as preconditions Optional.ofNullable(person) .ifPresent(IllegalArgumentException::new); Preconditions.checkNotNull(person); just stay with…

Slide 20

Slide 20 text

NESTED OPTIONALS Optional result = first.map(b -> second.map(b::add).orElse(b)) .map(Optional::of) .orElse(second); if(!first.isPresent() && !second.isPresent()) { return Optional.empty(); } return Optional.of( first.orElse(ZERO).add(second.orElse(ZERO))); just stay with…

Slide 21

Slide 21 text

OPTIONALS IN FIELDS AND PARAMS private final Optional car; public Optional car() { return this.car; } private final @Nullable Car car; public Optional car() { return Optional.ofNullable(this.car); } just stay with…

Slide 22

Slide 22 text

be lazy all the time public Person findOrCreate(PersonRequest request) { return repo.find(request.id()) .orElse(this.create(request)); } public Person findOrCreate(PersonRequest request) { return repo.find(request.id()) .orElseGet(() -> this.create(request)); } just stay with…

Slide 23

Slide 23 text

Optional.get() NoSuchElementException “Biggest Java 8 regret”

Slide 24

Slide 24 text

Key rules #1 Never use null for an Optional variable or return value; #2 Never use Optional.get(); #3 Don't use Optional just for chaining methods; #4 Don’t replace every single null reference with Optional; #5 Avoid using Optional in fields, parameters and collections;

Slide 25

Slide 25 text

Thank you. @ordepdev