New Java 8 feature -- Optional class

Keywords: Java

preface

Optional is a very important feature. Its main function is to solve the NPE(NullPointerException) problem!

Optional class

1. General

  Optional is not a functional interface, but a beautiful tool to prevent NullPointerException. This is an important concept in the next section. Let's quickly understand the working principle of Optional.

  Optional is a simple container whose value may or may not be null. Before Java 8, generally, a function should return a non empty object, but sometimes it returns nothing. In Java 8, you should return Optional instead of null.

2.API introduction

of

Create an Optional for a non null value.

The of() method creates an Optional class through a factory method. It should be noted that the parameters passed in when creating an object cannot be null. If the passed in parameter is null, a NullPointerException is thrown.

The code is as follows (example):

//Call the factory method to create an Optional instance
Optional<String> stringOpt = Optional.of("Deer can be seen in the depth of the forest");
//If the passed in parameter is null, a java.lang.NullPointerException is thrown
Optional<String> stringOpt1 = Optional.of(null);

ofNullable

Create an option for the specified value. If the specified value is null, an empty option will be returned.

ofNullable() is similar to the of method, except that it can accept null arguments.

The code is as follows (example):

//Create an Optional object that is allowed to be empty
Optional opt = Optional.ofNullable(null); //No error will be reported

empty

An empty Optional.

The code is as follows (example):

//An empty Optional
Optional<String> empty = Optional.empty();

isPresent

Returns true if the value exists; otherwise, returns false.

The code is as follows (example):

Optional<String> stringOpt = Optional.of("Deer can be seen in the depth of the forest");
//isPresent method returns true if the value exists; otherwise, it returns false.
if (stringOpt.isPresent()) {
    //Call get() within the Optional instance to return an existing value    
    System.out.println(stringOpt.get()); //Deer can be seen in the depth of the forest
}

get

The code is as follows (example):

//An empty Optional
Optional<String> empty = Optional.empty();
//Executing the following code will output: No value present
try {
    //Call get() on an empty Optional instance and throw NoSuchElementException
    System.out.println(empty.get());
} catch (NoSuchElementException ex) {
    System.out.println(ex.getMessage());
}

ifPresent

If the Optional instance has a value, call consumer for it, otherwise it will not be processed

The code is as follows (example):

//The ifPresent method accepts a lambda expression as a parameter. The lambda expression calls consumer to process the value of Optional
Optional.ofNullable(null).ifPresent(u ->  System.out.println("yes null Yes, no treatment"));
Optional.ofNullable("Deer can be seen in the depth of the forest").ifPresent(u ->  System.out.println("no null Yes, deal with it"));

//Output: not null, processing

Note: the value modified through ifPresent() will not change when obtained through get() again.

orElse

If there is a value, it will be returned; otherwise, it will return other specified values.

If the Optional instance has a value, it will be returned; otherwise, the parameter passed in by the orElse() method will be returned.

The code is as follows (example):

//If the value is not null, the orElse method returns the value of the Optional instance
//If null, returns the passed in specified pointer
Optional opt1 = Optional.ofNullable(null);
Optional opt2 = Optional.ofNullable("Deer can be seen in the depth of the forest");
System.out.println(opt1.orElse("Specified value")); //Specified value
System.out.println(opt2.orElse("Specified value")); //Deer can be seen in the depth of the forest

orElseGet

orElseGet() is similar to the orElse method, except that the default value is obtained. The orElse method takes the incoming string as the default value. The orElseGet method can accept the implementation of the Supplier interface to generate the default value.

The code is as follows (example):

//orElseGet is similar to orElse, except that orElseGet can accept a lambda expression to generate a default value
Optional opt1 = Optional.ofNullable(null);
Optional opt2 = Optional.ofNullable("Deer can be seen in the depth of the forest");
System.out.println(opt1.orElseGet( () -> "Specified value")); //Specified value
System.out.println(opt2.orElseGet( () ->"Specified value"));  //Deer can be seen in the depth of the forest

orElseThrow

If there is a value, it will be returned; otherwise, an exception created by the supplier interface will be thrown.

In the orElseGet method, we pass in a Supplier interface. However, in orElseThrow(), we can pass in a lambda expression or method to throw an exception if the value does not exist.

The code is as follows (example):

//Orelsethlow throws an exception generated by a lambda expression or method
//An empty Optional
Optional<String> empty = Optional.empty();
try {
    empty.orElseThrow( () -> new Exception() );
} catch (Throwable ex) {
    ex.printStackTrace();
}

map

If there is a value, call the mapping function to get the return value. If the return value is not null, an option containing the mapping return value is created as the return value of the map() method; otherwise, an empty option is returned.

The code is as follows (example):

//Map executes the passed lambda expression parameter to modify the value of the Optional instance. The return value of the lambda expression creates a new Optional instance as the return value of the map method
Optional<String> stringOpt = Optional.of("aBcDefg");
Optional<String> upperName = stringOpt.map((value) -> value.toUpperCase());
System.out.println(upperName.orElse("No value found"));

//Output: ABCDEFG

flatMap

If there is a value, execute the mapping function for it to return the return value of Optional type; otherwise, it returns null Optional. The flatMap() method is similar to the map (function) method, except that the mapper return value in the flatMap must be Optional. At the end of the call, flatMap does not optionally encapsulate the results.

The code is as follows (example):

//flatMap is very similar to map (Function), except for the return type of the lambda expression passed into the method
//The return value of the lambda expression in the flatMap method must be an Optional instance
Optional<String> stringOpt = Optional.of("aBcDefg");
Optional<String> upperName = stringOpt.flatMap((value) -> Optional.of(value.toUpperCase()));
System.out.println(upperName.orElse("No value found"));

//Output: ABCDEFG

filter

If there is a value and the assertion condition is met, the option containing the value is returned; otherwise, the empty option is returned.

The code is as follows (example):

//The filter method checks whether the given Option value meets some conditions. If so, it returns the same Option instance. Otherwise, it returns null Option
Optional<Integer> intOpt = Optional.of(5);
Optional<Integer> longName = intOpt.filter((value) -> value > 6);
System.out.println(longName.orElse(0)); //0

3.Optional application

  • Optional.of(obj): it requires that the incoming obj cannot be null, otherwise it will fall on the NullPointerException exception before entering the role
  • Optional.ofNullable(obj): it constructs an optional instance in an intelligent and tolerant way. Whoever comes will get Optional.empty(). If it is not null, it will call Optional.of(obj)

The code is as follows (example):

Optional<User> user = Optional.of(user1);
//orElse() map() may be concatenated infinitely to obtain the uppercase form of the user name. Otherwise, the default value is null
return user.map(u -> u.getUsername())
           .map(name -> name.toUpperCase())
           .orElse(null);

//orElseGet() is similar to orElse(), except that it uses a functional interface without a value
User result = Optional.ofNullable(user1).orElseGet( () -> user2);

//orElseThrow() if the user value is null, an IllegalArgumentException will be thrown
User result = Optional.ofNullable(user)
      .orElseThrow( () -> new IllegalArgumentException());

//The filter() decides to accept or reject the User based on basic email authentication
Optional<User> result = Optional.ofNullable(user)
      .filter(u -> u.getEmail() != null && u.getEmail().contains("@"));

When we want to assert that obj is not null, that is, we want to immediately report a NullPointException exception in case obj is null and modify it immediately instead of hiding the null pointer exception, we should decisively use option. Of (obj) to construct the Optional instance, and do not let any unpredictable null value have an opportunity to hide in Optional.

@Data
public class Student {
    private String name = "Deer can be seen in the depth of the forest";
    private String sex = "male";
}

// 1. Create an Optional object with an empty wrapper object value
Optional<Student> studentOpt = Optional.empty();
// 2. Create an Optional object with a non empty wrapper object value
Optional<Student> studentOpt1 = Optional.of(new Student());
// 3. Create an Optional object whose wrapper object value is allowed to be empty
Optional<Student> studentOpt2 = Optional.ofNullable(null);

System.out.println(studentOpt.get().getName()); // Printing: NoSuchElementException
System.out.println(studentOpt.orElse(new Student()).getName()); // Print: Deer in deep forest

System.out.println(studentOpt1.get().getName()); // Print: Deer in deep forest

System.out.println(studentOpt2.get().getName()); // Printing: NoSuchElementException
System.out.println(studentOpt2.orElse(new Student()).getName()); // Print: Deer in deep forest

System.out.println(studentOpt.isPresent()); // Print: false
System.out.println(studentOpt1.isPresent()); // Print: true

Optional can create objects of any type and obtain specific objects through the get() method. When the creation option is empty, the obtained object is empty, but it can be judged by orElse. If it is empty, it can be re created through orElse parameters. The isPresent() method is used to determine whether the object encapsulated by option is empty.

Student studentNull = null;
Student student = new Student();
Optional.ofNullable(studentNull).ifPresent(u ->  System.out.println("This object is null of"));
Optional.ofNullable(student).ifPresent(u ->  System.out.println("Is this object null of"));

//Output: is this object NULL

The ifPresent() method accepts a Consumer object (Consumer function). If the value of the wrapper object is not empty, run the accept() method of the Consumer object. In this way, you can happily use Lambda expressions.

Optional.ofNullable(studentNull)
        .filter(u -> "Deer can be seen in the depth of the forest".equals(u.getName()))
        .ifPresent(u ->  System.out.println("studentNull,The name is equal to the goal of "seeing deer in the deep forest""));
Optional.ofNullable(student)
        .filter(u -> "Deer can be seen in the depth of the forest".equals(u.getName()))
        .ifPresent(u ->  System.out.println("student,The name is equal to the goal of "seeing deer in the deep forest""));
Optional.ofNullable(student)
        .filter(u -> "Zhang San".equals(u.getName()))
        .ifPresent(u ->  System.out.println("student,The name is equal to the goal of "Zhang San""));

//Output: student, whose name is equal to the target of "deer in the deep forest"

The filter() method is also very practical. This method is used to filter the Optional object. If the conditions are met, the Optional object itself is returned. Otherwise, an empty Optional object is returned.

System.out.println(Optional.ofNullable(student).map(u -> u.getName()).get());
System.out.println(Optional.ofNullable(studentNull).map(u -> u.getName())); //u.getName()).get() will report an error
//Output:
//Deer can be seen in the depth of the forest
//Optional.empty
    
System.out.println(Optional.ofNullable(student).map(u -> u.getName()).orElse("This may be empty"));
System.out.println(Optional.ofNullable(studentNull).map(u -> u.getName()).orElse("This must be empty"));
//Output:
//Deer can be seen in the depth of the forest
//This must be empty

First, construct an Optional object with ofNullable() method and return the Optional object (if the student is null, return the map() method and return an empty Optional object). If u.getName()).get() cannot get, an exception will occur, so orElse is used instead.

Use the orElse method to replace the get method. The function of the orElse() method is relatively simple, that is, if the wrapped object value is not empty, return the wrapped object value, otherwise return the value of the input parameter other (the default value).

Posted by LucidParody on Wed, 01 Sep 2021 23:02:39 -0700