-
Notifications
You must be signed in to change notification settings - Fork 48
Optional
Hu JiaJun edited this page Nov 29, 2020
·
1 revision
- Simplify the judgment processing of null value in Java to prevent NPE (NullPointerException).
- Optional encapsulates an object and it contains an attribute
value
, which is the value of this object.
/* Optional source code */
public final class Optional<T> {
private final T value; // the value of the encapsulated object
...
}
public class Person {
private String name;
private int score;
Person(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public int getScore() {
return score;
}
}
/**
* This is a method to get the person's name.
* To prevent NullPointerException, must check whether the Person object
* is null before returning the name.
*/
/* Before Java 8 */
public static String getName(Person person) {
if (person == null) {
return "unknown";
}
return person.getName();
}
/* From Java 8 */
public static String getName(Person person) {
return Optional.ofNullable(person).map(p -> p.getName()).orElse("unknown");
}
/**
* Bad case (DON'T DO THIS)
* This case not only does not remove the null check process, but also add the Optional encapsulation process,
* which violates the original intention of Optional.
*/
public static String getName(Person person) {
Optional<Person> personOpt = Optional.ofNullable(person);
if (personOpt.isPresent()) {
return personOpt.get().getName();
}
return "unknown";
}
/* Optional source code */
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
...
}
From the Optional source code:
- The two constructor methods are private, so it is impossible to create Optional objects with
new Optional()
. - The Optional class provides three static methods
empty()
,of(T value)
,ofNullable(T value)
to create an Optional object.
- Create an empty Optional object
Optional optional = Optional.empty();
- Create an Optional object with a non-null value
- The value must be non-null, otherwise NullPointerException will be thrown.
Optional optional = Optional.of("optional");
- Create an Optional object with a nullable value
- The value can be null. If the value is null, the returned result is the same as Optional.empty().
Optional optional = Optional.ofNullable(null);
- The get() method is used to return the value of the encapsulated object. If the value of the encapsulated object is null, NoSuchElementException will be thrown. Therefore, the returned value does not need to determine whether it is null as long as no exception is thrown.
/* Optional source code */
public final class Optional<T> {
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
...
}
- Determine whether the value of the encapsulated object is null. not null -> true; null -> false
/* Optional source code */
public final class Optional<T> {
public boolean isPresent() {
return value != null;
}
...
}
- Determine whether the value of the encapsulated object is null. null -> true; not null -> false
/* Optional source code */
public final class Optional<T> {
public boolean isEmpty() {
return value == null;
}
...
- Accept a Consumer object, if the value of the encapsulated object is not null, then execute the accept() method of the Consumer object.
/* Optional source code */
public final class Optional<T> {
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
...
}
public static void printName(Person person) {
Optional.ofNullable(person).ifPresent(p -> System.out.println("The person's name is : " + p.getName()));
}
- Accept a Consumer object, if the value of the encapsulated object is not null, then execute the accept() method of the Consumer object; else then execute the Runnable object.
/* Optional source code */
public final class Optional<T> {
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
if (value != null) {
action.accept(value);
} else {
emptyAction.run();
}
}
...
}
public static void printName(Person person) {
Optional.ofNullable(person).ifPresentOrElse(
p -> System.out.println("The person's name is : " + p.getName()),
() -> System.out.println("unknown"));
}
- Accept a Predicate object to filter the Optional object. If it meets the conditions of the Predicate, return the Optional object itself, otherwise return an empty Optional object.
/* Optional source code */
public final class Optional<T> {
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent()) {
return this;
} else {
return predicate.test(value) ? this : empty();
}
}
...
}
public static void filterScore(Person person) {
Optional.ofNullable(person).filter(p -> p.getScore() >= 50).ifPresentOrElse(
p -> System.out.println(person.getName() + " passed"),
() -> System.out.println("The person failed"));
}
- Accept a Function object to perform operations on the value of the encapsulated object, and encapsulated the result into a new Optional object.
/* Optional source code */
public final class Optional<T> {
public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
// If the value of the encapsulated object is null
if (!isPresent()) {
return empty();
}
// If the value of the encapsulated object is not null
else {
// ofNullable() will return empty() if the result of mapper.apply(value) is null
return Optional.ofNullable(mapper.apply(value));
}
}
...
}
// The type of p.getName() is String, so the type of Optional<String> is also String.
public static Optional<String> getName(Person person) {
return Optional.ofNullable(person).map(p -> p.getName());
}
- Accept a Function object to perform operations on the value of the encapsulated object, and return the operated result.
/* Optional source code */
public final class Optional<T> {
public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
Objects.requireNonNull(mapper);
// If the value of the encapsulated object is null
if (!isPresent()) {
return empty();
}
// If the value of the encapsulated object is not null
else {
@SuppressWarnings("unchecked")
// throws NullPointerException if the result of mapper.apply(value) is null
Optional<U> r = (Optional<U>) mapper.apply(value);
return Objects.requireNonNull(r);
}
}
...
}
public static Optional<String> getName(Person person) {
return Optional.ofNullable(person).flatMap(p -> Optional.of(p.getName()));
}
System.out.println(getName(new Person("Oliver", 40)));
System.out.println(getName(new Person(null, 40)));
/* Output */
Oliver
Exception in thread "main" java.lang.NullPointerException
Method | Function Input | Function Output | Return |
---|---|---|---|
map() |
? super T |
? extends U |
Optional<U> |
flatMap() |
? super T |
? extends Optional<? extends U> |
Optional<U> |
Peer Learning
Codecrunch Contributions
Piazza Contributions
Wiki Contributions
Guides
Setting Up Checkstyle
Setting Up Java
Setting Up MacVim
Setting Up Sunfire
Setting Up Unix For Mac
Setting Up Unix For Windows
Setting Up Vim
Setting up SSH Config
CS2030 Contents
Lecture 1 SummaryCompile-run vs Run-time Summary
Quick Guide To Abstraction
Generics and Variance of Types
Comparable vs Comparator
Summary of completable future
CS2030S Notes
ELI5 Optional.map vs Optional.flatMap
PECS Example Code
Java Collection Framework (Iterator)
Generic
Generic Type Parameter and Generic Wildcard
Calculator
Lambda-Expression
Single Abstract Method (SAM)
Method Reference
Functional Interfaces 2
Simple Usage of Sandbox
Associative-but-not-commutative
Higher Order function
Functional Programming
Calculator With Functor
Eager Evaluation VS Lazy Evaluation
Simple Usage of Lazy Evaluation
Lazy Evaluation for LazyList
Lazy Evaluation for BinaryTree
Stream
Parallel Stream
Optional
Simple Usage of Stream
Asynchronous Programming
Notes on CompletableFuture
Notes on CompletableFuture 2
Simple Usage of CompletableFuture
Mind Map
Exception Handling
Links
CS2030 Java Style Guide
CS2030 Javadoc Specification
JDK 11 Download Link
JDK 11 API Docs
Codecrunch
Piazza Forum