Introduction to the
The optional class is an elegant solution to the NPE problem introduced in java8, and one that source authors hope will replace null.
history
In 1965, a British computer scientist named Tony Hoare came up with the idea of null references while designing ALGOL W. Hoare chose null references “just because it’s so easy to implement.” Years later, he came to regret his decision, calling it “my million-dollar mistake.” We’ve already seen what happens when a programmer checks an object’s field to see if its value is in the expected format, only to discover that instead of looking at an object, we’re looking at a null pointer, which immediately throws an annoying NullPointerException [1].
Problems with NULL
-
A source of error.
NullPointerException is the most typical exception in Java program development today.
-
Code bloat.
It leaves your code riddled with deeply nested null checks and horribly unreadable.
-
It’s meaningless on its own.
Null has no semantics of its own; in particular, it represents the wrong way to model missing variable values in statically typed languages.
-
Broke the Java philosophy.
Java tries to keep programmers from being aware of Pointers, with one exception: null Pointers.
-
A crack in the Java type system.
Null is not of any type, which means it can be assigned to any variable that references a type. This can cause problems because when the variable is passed to another part of the system, you cannot know what type the null variable was originally assigned to.
plan
Taking inspiration from Haskell and Scala, a new class java.util.Optional<T> was introduced in Java 8. This is a class that encapsulates Optional values. For example, using the new class means that if you know that a person may or may not have a school, the school variable inside the Student class should not be declared Schoold, and a null reference should be assigned to it when encountering a Student who does not have a school. Instead, declare it as an Optional<School> type directly, as in this article.
The scene is introduced into
Let’s start with two common scenarios
/** * >1; /** * >1
public static boolean checkIsPublicV1(Student student) {
if(student ! =null) {
School school = student.getSchool();
if(school ! =null) {
returnschool.isPublicFlag(); }}throw new RuntimeException("Abnormal parameter");
}
public static String getAdultV1(Student student) {
if(student ! =null) {
int age = student.getAge();
if (age > 18) {
returnstudent.getName(); }}return "No";
}
Copy the code
The above approach is a common reading process. Optional is a solution to the problem of code appreciation caused by every null judgment
Method statement
The constructor
- Optional(T var1)
The source code
private final T value;
private Optional(a) {
this.value = null;
}
private Optional(T var1) {
this.value = Objects.requireNonNull(var1);
}
Copy the code
The optional constructor is private and cannot be created directly. It can only be created through other static methods in the class. The Optional constructor supports a generic input parameter and cannot be null
Create an Optional object
- Declare an empty Optional: Optional
empty()
- Create Optional: Optional
of(T var0) with a non-null value
- Optional: Optional
ofNullable(T var0)
The source code
The empty () the source code
private static finalOptional<? > EMPTY =new Optional();
private Optional(a) {
this.value = null;
}
public static <T> Optional<T> empty(a) {
Optional var0 = EMPTY;
return var0;
}
Copy the code
The Optional class maintains a null object that can be returned using the empty static method
Source of var0 (T)
public static <T> Optional<T> of(T var0) {
return new Optional(var0);
}
Copy the code
Return the usual parameter constructor. Note that since the constructor requires that the input parameter cannot be empty, an NPE exception will still be raised if the input parameter of the of method is empty
Var0 ofNullable (T) the source code
public static <T> Optional<T> ofNullable(T var0) {
return var0 == null ? empty() : of(var0);
}
Copy the code
This method complements the ofNullable method by returning a constructor if the ofNullable parameter is not null, and an optional object with a null value when the ofNullable parameter is null. OfNullable is better than of in most scenarios.
Is there any essential difference between null references and option.empty ()? Semantically, you can think of them as the same thing, but in practice they are very different: If you try to dereference a NULL, NullPointerException will be triggered, but using option.empty () is completely fine. It is a valid object of the op-tional class and can be called in many situations, which is very useful.
For example,
public static void testOptionalBuild(a) {
New 'Optional()' has private access in 'java.util.Optional'
// Optional<School> school = new Optional<>();
// 2. Of builds non-null and NullPointerException
/*Optional
o1 = Optional.of("test"); System.out.println(o1); Optional
// 3. OfNullable builds non-empty and empty objects (option.empty)
/*Optional
o3 = Optional.ofNullable("test"); System.out.println(o3); Optional
}
Copy the code
Extract and convert values from Optional objects using Map
- Optional<U> map(Function<? super T, ? extends U> var1)
The source code
public <U> Optional<U> map(Function<? super T, ? extends U> var1) {
Objects.requireNonNull(var1);
return !this.isPresent() ? empty() : ofNullable(var1.apply(this.value));
}
Copy the code
Empty objects are returned directly when the optional package is empty, otherwise the function.apply method in the input parameter is executed
Link Optional objects using flatMap
- Optional<U> flatMap(Function<? super T, Optional<U>> var1)
The source code
public <U> Optional<U> flatMap(Function<? super T, Optional<U>> var1) {
Objects.requireNonNull(var1);
return !this.isPresent() ? empty() : (Optional)Objects.requireNonNull(var1.apply(this.value));
}
Copy the code
Almost the same as map. Note that in the Function. Apply method, the return type is optional
For example,
public static void testOptionalMap(a) {
Student student1 = getDefaultStudent();
Student student2 = getBackStudent();
// map
String school1 = Optional.ofNullable(student1).map(i -> i.getName()).orElse("Unknown");
String school2 = Optional.ofNullable(student2).map(i -> i.getName()).orElse("Unknown");
System.out.println("school1: " + school1 + "| school2: " + school2);
/ / flapMap chain
String school3 = Optional.ofNullable(getOptionalStudent()).flatMap(i -> getOptionalStudent()).flatMap(i->i.getSchool()).map(i->i.getSchoolName()).orElse("Didn't go to college.");
System.out.println("school3: " + school3);
}
Copy the code
Default behavior and dereference Optional object 1
- T orElse(T var1)
- T orElseGet(Supplier<? extends T> var1)
- T orElseThrow(Supplier<? extends X> var1)
Note: These three methods are not static methods, so they need to be called from an instance object, usually followed by the ofNullable method to handle null or return values
The source code
OrElse the source code
public T orElse(T var1) {
return this.value ! =null ? this.value : var1;
}
Copy the code
Returns the package value in Optional if the package value is not empty, or in orElse if it is empty
OrElseGet source
public T orElseGet(Supplier<? extends T> var1) {
return this.value ! =null ? this.value : var1.get();
}
public T get(a) {
if (this.value == null) {
throw new NoSuchElementException("No value present");
} else {
return this.value; }}Copy the code
Similar to the previous method, returns the package value if the package value in Optional is not empty, or executes the Supplier method in orElseGet if it is empty
OrElseThrow source
public <X extends Throwable> T orElseThrow(Supplier<? extends X> var1) throws X {
if (this.value ! =null) {
return this.value;
} else {
throw(Throwable)var1.get(); }}Copy the code
Similarly, return the package value in Optional if the package value is not null, or throw the Supplier. Get exception method in orElseThrow if the package value is null
For example,
public static void testOptionalOrElse(a) {
// orElse
Student stu = getDefaultStudent();
Student backStudent = getBackStudent();
Student realStu1 = Optional.ofNullable(stu).orElse(backStudent);
System.out.println(realStu1);
// orElseGet
Student realStu2 = Optional.ofNullable(stu).orElseGet(()-> getBackStudent());
System.out.println(realStu2);
// orElseGet
Student realStu3 = Optional.ofNullable(stu).orElseThrow(()-> new RuntimeException("Students do not exist."));
System.out.println(realStu3);
}
Copy the code
Default behavior and dereference Optional object 2
- boolean isPresent()
- void ifPresent(Consumer<? super T> var1)
The source code
IsPresent () the source code
public boolean isPresent(a) {
return this.value ! =null;
}
Copy the code
The user determines whether the value of the optional package is empty and returns a Boolean value
IfPresent (Consumer var1) source
public void ifPresent(Consumer<? super T> var1) {
if (this.value ! =null) {
var1.accept(this.value); }}Copy the code
If the value of the optional package is not null, the user continues processing the consumer.accept method in the input parameter. Similar to the if (var. =null) {do sth}
For example,
public static void testOptionalIfPresent(a) {
// isPresent()
Student student1 = getDefaultStudent();
Student student2 = getBackStudent();
boolean b1 = Optional.ofNullable(student1).isPresent();
boolean b2 = Optional.ofNullable(student2).isPresent();
System.out.println("b1: " + b1 + "| b2: " + b2);
// isPresent(Consumer)
Optional.ofNullable(student2).ifPresent(i-> acceptStudent(i, LocalDate.now()));
}
Copy the code
Use filter to filter out specific values
- Optional filter(Predicate<? super T> var1)
The source code
public Optional<T> filter(Predicate<? super T> var1) {
Objects.requireNonNull(var1);
if (!this.isPresent()) {
return this;
} else {
return var1.test(this.value) ? this: empty(); }}Copy the code
Filter optional objects. Returns the optional package value if it is not null, or executes the Predicate. Test method of the filter entry
For example,
public static void testOptionalFilter(a) {
Student student1 = getDefaultStudent();
Student student2 = getBackStudent();
System.out.println(student1);
System.out.println(student2);
Student student3 = Optional.ofNullable(student1).filter(i -> i.getAge() > 18).orElse(getBackStudent());
Student student4 = Optional.ofNullable(student2).filter(i -> i.getAge() > 18).orElse(getBackStudent());
System.out.println(student3);
System.out.println(student4);
}
Copy the code
In actual combat
The optional class has been explained for the most part. Back to the beginning, the scene mentioned is introduced and transformed with Optional
/** * Update the original checkIsPublicV1 */
public static boolean checkIsPublicV2(Student student) {
return Optional.ofNullable(student).map(i -> i.getSchool()).map(i -> i.isPublicFlag()).orElseThrow(() -> new RuntimeException("Abnormal parameter"));
}
/** * getAdultV1 */
public static String getAdultV2(Student student) {
return Optional.ofNullable(student).filter(i->i.getAge()>18).map(i->i.getName()).orElseGet(()->getDefaultStudent().getName());
}
Copy the code
The attached:
Add the code
public static void main(String[] args) {
// Release one by one
/ / introduction
// System.out.println(checkIsPublicV1(stu2));
// System.out.println(getAdultV1(stu2));
/ / optional methods
// testOptionalBuild();
// testOptionalOrElse();
// testOptionalIfPresent();
// testOptionalMap();
// testOptionalFilter();
/ / field
// System.out.println(getAdultV2(stu3));
// System.out.println(checkIsPublicV2(stu3));
}
/**======== model data =======**/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
static class Student {
private String name;
private int age;
private School school;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
static class School {
private String schoolName;
private boolean publicFlag;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
static class StudentOpt {
private String name;
private int age;
private Optional<School> school;
}
public static Student getDefaultStudent(a) {
return null;
}
public static Student getBackStudent(a) {
return Student.builder().name("Little red").age(19).build();
}
public static Optional<StudentOpt> getOptionalStudent(a) {
return Optional.ofNullable(StudentOpt.builder().name("Little mo").age(18)
.school(Optional.ofNullable(School.builder().schoolName(The University of Blue Whale).publicFlag(true).build())).build());
}
public static void acceptStudent(Student stu, LocalDate date) {
System.out.println("Date:" + date + "A new student:" + stu.getName());
}
Copy the code
[1] Java8
For detailed source code, please refer to: github.com/chetwhy/clo…