Using Optional


Once called a Billion-dollar mistake. NullPointerException is by far one of the most frequent exceptions in Java and since version 8 we can use it as a way to avoid this exception. Optional is a container that can has a value or not. In this technical post we will review basic concepts about Optional. Please consider this example where we are creating an empty optional.

@Test
void shouldCreateAnEmptyOptional() {
  Optional<String> empty = Optional.empty();
  assertFalse(empty.isPresent(), "should not be present");
}

Here is another way to create an optional

@Test
@DisplayName("should validate if is present")
void shouldBePresentBy(){
  String nickname = "josdem"
  Optional<String> opt = Optional.of(nickname);
  assertTrue(opt.isPresent(), "should be present");
}

If some values could be null, you can use ofNullable() method.

@Test
@DisplayName("should validate if is present by nullable")
  void shouldBePresentByNullable(){
  Optional<String> opt = Optional.ofNullable("josdem");
  assertTrue(opt.isPresent(), "should be present by nullable");
}

So, you can validate if a value is not null

@Test
@DisplayName("should validate when is not present")
void shouldNotBePresent() {
  Optional<String> opt = Optional.ofNullable(null);
  assertFalse(opt.isPresent(), "should not be present");
}

You can take an action if value is present

@Test
@DisplayName("should take action if is present")
void shouldPrintValue(){
  Optional<String> opt = Optional.ofNullable("josdem");
  opt.ifPresent(value -> log.info("value: " + opt.get()));
}

If a value is not present, you can return a default value

@Test
@DisplayName("should display default value")
void shouldDisplayDefault(){
  String value = null;
  String name = Optional.ofNullable(value).orElse(StringUtils.EMPTY);
  assertEquals(StringUtils.EMPTY, name, "should be empty");
}

Or throwing an exception

@Test
@DisplayName("should throw an exception")
  void shouldThrowAnException(){
  String value = null;
  assertThrows(RuntimeException.class, () -> Optional.ofNullable(value).orElseThrow(RuntimeException::new), "should throw an exception");
}

Using Optional in Collections

Here are some examples how to filter non-empty values in collections

@Test
@DisplayName("should get a list non empty values")
void void shouldGetNonEmptyValuesList(){
  List<Optional<String>> staff = Arrays.asList(
    Optional.of("developer"), Optional.of("designer"), Optional.empty(), Optional.of("developer"));

  List<String> filteredStaff = staff.stream()
    .flatMap(Optional::stream)
    .collect(Collectors.toList());

  assertEquals(EXPECTED_VALUES, filteredStaff.size(), "should be 3 non empty values");
}

With Optional::Stream we are getting sequential stream of the only value present. Here is another way to do it

@Test
@DisplayName("should filter by developer")
void shouldFilterByDeveloper(){
  List<Optional<String>> staff = Arrays.asList(
    Optional.of("developer"), Optional.of("designer"), Optional.empty(), Optional.of("developer"));

  List<String> developers = staff.stream()
    .filter(it -> it.isPresent())
    .map(it -> it.get())
    .filter(it -> it.equals("developer"))
    .collect(Collectors.toList());

  assertEquals(EXPECTED_DEVELOPERS, developers.size(), "should be two developers");
}

With .filter and .map we are doing the same as Optional::Stream, plus we are filtering only developer values.

To browse the code go here, to download the code:

git clone https://github.com/josdem/java-workshop.git
cd optional

To run the code:

gradle test

Return to the main article