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