preface

Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”. Optional is a new feature introduced in Java 8. It is designed to help programmers with NPE (NullPointerException) issues. However, many people use it in their projects because it is readable. Else, in my opinion, since Optional has been launched, it must have the value and significance to use it, it is necessary to learn to understand it, after master to write elegant and slightly advanced sense of code! Hopefully Optional will be an Option in your coding process.

introduce

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

Optional is a container object that may or may not contain non-null values. Essentially, it is a wrapper class that holds values of any specific Java type that can be retrieved using the GET method.

Static method to create an instance

Optional.empty()

  • To create an empty Optional instance
System.out.println(Optional.empty()); // Optional.empty
Copy the code

Optional.of(T value)

  • Creates an Optional instance with the specified current non-null value

  • Notice that the value passed in is not null; otherwise, NPE is reported

The sample

// The object property is null, not null
User emptyUser = new User();
System.out.println(Optional.of(emptyUser));

// The User object is empty
User nullUser = null;
System.out.println(Optional.of(nullUser)); // throw NullPointerException

// The String object is empty
String nullString = null;
System.out.println(Optional.of(nullString)); // // throw NullPointerException
Copy the code

Optional.ofNullable(T value)

  • Returns Optional describing the specified value if the value is non-empty, otherwise returns option.empty () without raising an exception

The sample

// The object property is null, not null
User emptyUser = new User();
System.out.println(Optional.ofNullable(emptyUser)); // Optional[User{id=null, name='null', sex='null', age=null, salary=null}]

// The User object is empty
User nullUser = null;
System.out.println(Optional.ofNullable(nullUser)); // Optional.empty

// The String object is empty
String nullString = null;
System.out.println(Optional.ofNullable(nullString)); // Optional.empty
Copy the code

summary

  • Before using Optional, you need to create instances using the above three static methods

  • Create an empty instance using option.empty ()

  • If you want to create a non-null instance, you are advised to use optional.ofNullable (). If you can specify that the parameter is not null, you can use option.of ().

Common instance methods

isPresent()

  • Used to determine whether the wrapper value exists, returning true if it does, false otherwise

The sample

Optional<User> opt1 = Optional.of(emptyUser); // Optional[User{id=null, name='null', sex='null', age=null, salary=null}]

Optional<User> opt2 = Optional.ofNullable(nullUser); // Optional.empty

System.out.println(opt1.isPresent() ? "Package value exists" : "Package value does not exist"); // The package value exists
System.out.println(opt2.isPresent() ? "Package value exists" : "Package value does not exist"); // The package value does not exist
Copy the code

ifPresent(Consumer<? super T> consumer)

  • If the Optional instance has a value, call the function object consumer for it; otherwise, no action is taken

How to understand the functional interface Consumer?

// Consumer methods
private static void consumerMethod(User user, Consumer<User> cu) {
    cu.accept(user);
}

// main called in the main method
User user01 = new User(42."Shi Tiangou"."Female".16.4520);
consumerMethod(user01, user1 -> System.out.println(user1.getName() + user1.getSex())); // Shi Tiangou female
Copy the code

A Consumer is a Consumer interface that receives a snippet of interface code or a Lambda expression. The common method is the Accept () method, an abstract method that consumes a value passed in without returning a value. Consume functions (or snippets of code) and encapsulate logical code.

The sample

// Opt1 and opt2 are defined above
opt1.ifPresent(System.out::println); // User{id=null, name='null', sex='null', age=null, salary=null}
opt2.ifPresent(System.out::println); // There is no output
Copy the code

get()

  • If the wrapper value exists, it is taken from the Optional wrapper and returned, otherwise NoSuchElementException is thrown

The sample

User user = opt1.get();
opt2.get(); // throw NoSuchElementException: No value present
System.out.println(user); // User{id=null, name='null', sex='null', age=null, salary=null}
Copy the code

orElse(T other)

  • Return this value if it exists, otherwise return other

The sample

User user02 = new User(20."Bill"."Female".15.2350);
Opt2 is null, so return other => user02
User orElse = opt2.orElse(user02); 
System.out.println(orElse); / / User {id = 20, name = 'bill', sex = 'female' and age = 15, salary = 2350}
Copy the code

orElseGet(Supplier<? extends T> other)

  • Return the value if it exists, otherwise call other and return the result of the call. The Supplier parameter receives the implementation of the Supplier interface. Optional returns the value if it contains a value, otherwise the return value is retrieved from the Supplier

How do I understand the functional interface Supplier?

// Provider/vendor approach
private static User supplierMethod(Supplier<User> su) {
    return su.get();
}

// main called in the main method
User user03 = new User(42."Pockmarked seed"."Male".29.4000);
System.out.println(supplierMethod(() -> user03)); / / User {id = 42, name = 'just soso' sex = 'male', the age = 29, salary = 4000}
Copy the code

Supplier is a provider interface that receives interface code snippet or Lambda expression. The general method is to use get() method. This abstract method gets the result of whatever data is passed in. Functions (or code snippets) are provided and logical code is encapsulated.

The sample

orElseThrow(Supplier<? extends X> exceptionSupplier)

  • Returns the included value, if present, otherwise throws the exception created by exceptionSupplier

The sample

try {
    // opt2 is null, so the provided exception is thrown
    User elseThrow = opt2.orElseThrow(NullPointerException::new);
    System.out.println(elseThrow);
}catch (Exception e) {
    System.out.println(e); // java.lang.NullPointerException
}
Copy the code

filter(Predicate<? super T> predicate)

  • If the wrapper value exists and matches the predicate conditions, an Optional describing the value is returned, otherwise Optional. Empty is returned

The sample

Optional<User> opt = Optional.ofNullable(user02)
        .filter(u2 -> u2.getSalary() > 6000);
        
// Conditions for the predicate do not meet
System.out.println(opt); // Optional.empty
Copy the code

map(Function<? super T,? extends U> mapper)

Source code analysis

public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if(! isPresent())return empty();
    else {
        returnOptional.ofNullable(mapper.apply(value)); }}Copy the code
  • If a value exists, the application provides a mapping function to it that returns an Optional wrapped in option.ofNullable

The sample

Integer newNameLens =
        Optional.of(user03) // Optional<User>
                .map(u3 -> u3.getName() + The '-' + u3.getSex()) // This returns Optional
      
                .map(newName -> newName.trim()) // This returns Optional
      
                .map(newName -> newName.length()) // This returns Optional
      
                .get(); // Fetch the value wrapped in Optional
                
System.out.println("New name length after Map processing:" + newNameLens); // After the Map processing, get the new name length: 5
Copy the code

flatMap(Function<? super T,Optional> mapper)

Source code analysis

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    Objects.requireNonNull(mapper);
    if(! isPresent())return empty();
    else {
        returnObjects.requireNonNull(mapper.apply(value)); }}Copy the code
  • If a value exists, apply a mapping function to it, which returns an Optional wrapped in objects.requirenonNULL. If the mapping function is null, the NPE is reported

The sample

user02.setName("Zhuge power");
String firstName = Optional.ofNullable(user02) // // returns Optional
      
        .flatMap(u2 -> Optional.of(u2.getName())) // This returns Optional
      
        .flatMap(name -> {
            String familyName;
            if (name.length() <=3) {
                familyName = name.substring(0.1);
            } else {
                familyName = name.substring(0.2);
            }
            return Optional.of(familyName);
        }) // This returns Optional
      

System.out.println("User name and last name after flatMap processing:" + firstName); / / various ge
Copy the code

summary

  • Whenever a wrapper value exists, you get the Optional that describes the value

  • Use static ofNullable() when creating Optional wrapper classes with orElse at the end of the chain. In addition, isPresent() can be used to declare null and ifPresent() to consume the possible wrapper value. In this case, it does not matter if the value is null, and NPE will not be processed and reported

  • The Optional instance method map() differs from flatMap() in that one mapping function results in a concrete value and can be null, while the latter is Optional and cannot be null otherwise NPE arrangements

Scenario using

A null value transformation

String avatarUrl = null;
User user = new User("HUALEI", url);

String userAvatarUrl = Optional.ofNullable(user)
                       .map(u -> u.getUserAvatar()).orElse("https://p3-passport.byteacctimg.com/img/user-avatar/7c53d8cf8b3f3de699f1db654b88063d~300x300.image");

user.setUserAcatar(avatarUrl);
Copy the code

If no profile picture is set, the default profile picture is used.

Integer salary = Optional.ofNullable(emptyUser)
        .map(u -> u.getSalary())
        .orElse(0);

emptyUser.setSalary(salary);
Copy the code

If the employee does not have an initial salary, it defaults to 0.

Value to filter

Verify the mobile phone number format, written as follows:

String phone = "12345678910";
String regex = "^ ([0-9] (13) | | (14 [5] | 7) (15 ([0, 3] | [5-9])) | | (17 [013678]) (18 [0, 5-9])) \ d {8} $";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(phone);
boolean isMatch = m.matches();
if(isMatch){
    System.out.println("Correct format of mobile phone number");
} else {
    System.out.println("Mobile phone number format error");
}
Copy the code

Filter using the option.filter () method

boolean isValid = Optional.ofNullable(user)
                                .filter(u -> {
                                    Pattern pattern = Pattern.compile(regex);
                                    return pattern.matcher(u.getPhone()).matches();
                                })
                                .isPresent();

assertTrue(isValid);
Copy the code

Mixed operation

Employees list

User user01 = new User(42."Shi Tiangou"."Female".16.4520);
User user02 = new User(20."Bill"."Female".15.2350);
User user03 = new User(42."Pockmarked seed"."Male".29.4000);
List<User> users = new ArrayList<User>() {{
    add(user01);
    add(user02);
    add(user03);
}};
Copy the code

To find the total salary of the employees, we might have written this before:

// Calculate the salary accumulator
int sumSalary = 0;

// Add up the salary of each non-empty user in the enhanced for loop
if(users ! =null) {
    for (User u : users) {
        if(u ! =null) {
            sumSalary += u.getSalary();
        }
    }
}

System.out.println("Total employee salary:" + sumSalary); // Total employee salary: 10870
Copy the code

If you read the functional operations on the stream – juejin (cn), you might write something like this:

Integer sumSalary = 0;

if(users ! =null) {
    sumSalary = users.stream()
            .filter(Objects::nonNull)
            .map(User::getSalary)
            .reduce(0, (sum, currentValue) -> sum + currentValue);
}

System.out.println("Total employee salary:" + sumSalary); // Total employee salary: 10870
Copy the code

But would you write that?

Integer sumSalary = Optional.ofNullable(users).map(us -> {
    Integer sum = 0;
    for (User user : us) {
        sum += Optional.ofNullable(user).map(User::getSalary).orElse(0);
    }
    return sum;
}).orElse(0);

System.out.println("Total employee salary:" + sumSalary); // Total employee salary: 10870
Copy the code

At the end

Writing is not easy, welcome everyone to like, comment, your attention, like is my unremitting power, thank you to see here! Peace and Love.