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 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 assigned a null reference when confronted with a Student who does not have a school. Instead, it should be declared directly as Optional, as in this article.

The scene is introduced into

Let’s start with two common scenarios

*/ public static Boolean checkIsPublicV1(Student Student) {if (Student Student! = null) { School school = student.getSchool(); if (school ! = null) { return school.isPublicFlag(); }} throw new RuntimeException(" parameter exception "); } public static String getAdultV1(Student student) { if (student ! = null) { int age = student.getAge(); if (age > 18) { return student.getName(); }} return "none "; } Duplicate codeCopy 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() { this.value = null; } private Optional(T var1) { this.value = Objects.requireNonNull(var1); } Duplicate codeCopy 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 final Optional<? > EMPTY = new Optional(); private Optional() { this.value = null; } public static <T> Optional<T> empty() { Optional var0 = EMPTY; return var0; } Duplicate codeCopy 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); } Duplicate codeCopy 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); } Duplicate codeCopy 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() { // 1. New 'Optional()' has private access in 'java.util.Optional' // Optional<School> School = new Optional<>(); /*Optional<String> o1 = Optional. Of ("test"); System.out.println(o1); Optional<Object> o2 = Optional.of(null); System.out.println(o2); /*Optional<String> o3 = option.ofnullable ("test"); System.out.println(o3); Optional<Object> o4 = Optional.ofNullable(null); System.out.println(o4); */} Copy the codeCopy the code

Extract and convert values from Optional objects using Map

  • Optional 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)); } Duplicate codeCopy 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 flatMap(Function<? super T, Optional> 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)); } Duplicate codeCopy 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() { Student student1 = getDefaultStudent(); Student student2 = getBackStudent(); // map String school1 = Optional. OfNullable (student1).map(I -> i.gename ()).orelse (" unknown "); String school2 = Optional. OfNullable (student2).map(I -> i.gename ()).orelse (" unknown "); System.out.println("school1: " + school1 + "| school2: " + school2); FlapMap school3 = Optional. OfNullable (getOptionalStudent()).flatMap(I -> GetOptionalStudent ()).flatMap(I -> i.goetSchool ()).map(I -> i.goetSchoolName ()).orelse (" didn't go to college "); System.out.println("school3: " + school3); } Duplicate codeCopy 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; } Duplicate codeCopy 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() { if (this.value == null) { throw new NoSuchElementException("No value present"); } else { return this.value; }} Copy the codeCopy 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 codeCopy 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() { // 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()); // orElseGet Student realStu3 = Optional. System.out.println(realStu3); } Duplicate codeCopy 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() { return this.value ! = null; } Duplicate codeCopy 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 codeCopy 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() { // 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())); } Duplicate codeCopy 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 codeCopy 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() { 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); } Duplicate codeCopy 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

*/ public static Boolean checkIsPublicV2(Student Student) {return Optional.ofNullable(student).map(i -> i.getSchool()).map(i -> i.isPublicFlag()).orElseThrow(() -> new RuntimeException(" parameter exception ")); } public static String getAdultV2(Student Student) {return Optional.ofNullable(student).filter(i->i.getAge()>18).map(i->i.getName()).orElseGet(()->getDefaultStudent().getName()); } Duplicate codeCopy the code

The attached:

Add the code

Public static void main(String[] args) {// release // import // system.out.println (checkIsPublicV1(stu2)); // System.out.println(getAdultV1(stu2)); // optional method // testOptionalBuild(); // testOptionalOrElse(); // testOptionalIfPresent(); // testOptionalMap(); // testOptionalFilter(); // 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() { return null; } public static Student getBackStudent() {return student.builder ().name().age(19).build(); } public static Optional<StudentOpt> getOptionalStudent() { return Optional. OfNullable (StudentOpt. Builder (). The name (" little mo "). The age (18) .school(Optional. OfNullable (school.builder ().schoolName(" blue Blue University ").publicFlag(true).build())).build()); } public static void acceptStudent(Student stu, LocalDate date) {system.out.println (" "+ date +"); " + stu.getName()); } Duplicate codeCopy the code

[1] Java8

For detailed source code, please refer to: github.com/chetwhy/clo…