Optional is a good thing, do you really know how to use it?

Click on the “Java base” above, select “Set as star”

Be a positive person, not a positive waste person!

Update articles every day at 14:00, lose a million bits of hair every day…

Source code boutique column

  • Original | Java 2021 Super God Road, very liver~

  • An open source project with detailed annotations in Chinese

  • RPC framework Dubbo source code analysis

  • Network application framework Netty source code analysis

  • Message middleware RocketMQ source code analysis

  • Database middleware Sharding-JDBC and MyCAT source code analysis

  • Job Scheduling Middleware Elastic-Job Source Code Analysis

  • Distributed transaction middleware TCC-Transaction source code analysis

  • Eureka and Hystrix source code analysis

  • Java Concurrency Source Code

Source: blog.csdn.net/zjhred/

article/details/84976734

  • introduction

  • API introduction

  • Actual use

86d65b307a3a9b9a831d5e6b28ef84df.jpeg

Introduction

At the beginning of the article, let’s talk about the NPE problem. The NPE problem is the NullPointerException that we often encounter in development. Suppose we have two classes, and their UML class diagram is shown in the figure below

c2dcb014647a86c1567e2dad3e17ec16.png

o_optional1.png

In this case, there is code like

user.getAddress().getProvince();

This way of writing, when the user is null, it is possible to report a NullPointerException. In order to solve this problem, the following writing method is used

if(user!=null){
    Address address = user. getAddress();
    if(address!=null){
        String province = address. getProvince();
    }
}

This way of writing is relatively ugly. In order to avoid the above-mentioned ugly way of writing, let the ugly design become elegant. JAVA8 provides the Optional class to optimize this writing method, which will be described in detail in the following text

Background management system + user applet based on Spring Boot + MyBatis Plus + Vue & amp; Element, supports RBAC dynamic permissions, multi-tenancy, data permissions, workflow, three-party login, payment, SMS, mall and other functions

  • Project address: https://github.com/YunaiV/ruoyi-vue-pro

  • Video tutorial: https://doc.iocoder.cn/video/

API Introduction

First introduce the API. Unlike other articles, this article uses an analogy and combines the source code. Unlike other articles, APIs are listed one by one, making people unable to find the focus.

1. Optional(T value), empty(), of(T value), ofNullable(T value)

There is a correlation between these four functions, so they are stored in a group.

Let me explain first, Optional(T value), that is, the constructor, has private authority and cannot be called from the outside. The remaining three functions are public permissions for us to call. Then, the essence of Optional is that a real value is stored inside, and when it is constructed, it is directly judged whether its value is empty. Well, it’s still relatively abstract. Go directly to the source code of the Optional(T value) constructor, as shown in the figure below

ac6ecb8c299a6d8779719de4024d3167.png

o_optional2png.png

Then, the source code of of(T value) is as follows

public static <T> Optional<T> of(T value) {
    return new Optional<>(value);
}

That is to say, the of(T value) function calls the constructor internally. According to the source code of the constructor, we can draw two conclusions:

  • The Optional object constructed by the of(T value) function will still report NullPointerException when the Value is empty.

  • The Optional object constructed by the of(T value) function, when the Value value is not empty, the Optional object can be constructed normally.

In addition, the Optional class also maintains an object whose value is null, which is probably as follows

public final class Optional<T> {
    //Omit....
    private static final Optional<?> EMPTY = new Optional<>();
    private Optional() {
        this. value = null;
    }
    //Omit...
    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }
}

Then, the function of empty() is to return the EMPTY object.

Well, after laying the groundwork so much, it can be said that ofNullable(T value) works, and the source code

public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}

Well, everyone should understand what it means. Compared with of(T value), the difference is that when the value is null, of(T value) will report NullPointerException; ofNullable(T value) will not throw Exception, ofNullable(T value) directly returns an EMPTY object.

Does that mean that we only use the ofNullable function in the project instead of the of function?

No, when something exists, it naturally has the value of existence. We don’t want to hide NullPointerException when we are running. Instead, report immediately, in which case the Of function is used. But I have to admit that such scenes are really rare. Bloggers have only used this function in writing junit test cases.

2. orElse(T other), orElseGet(Supplier other) and orElseThrow(Supplier exceptionSupplier)

These three functions are stored in a group and are called when the value passed in by the constructor is null. The usage of orElse and orElseGet is as follows, which is equivalent to giving a default value when the value is null:

@Test
public void test() {
    User user = null;
    user = Optional.ofNullable(user).orElse(createUser());
    user = Optional.ofNullable(user).orElseGet(() -> createUser());

}
public User createUser(){
    User user = new User();
    user.setName("zhangsan");
    return user;
}

The difference between these two functions: when the user value is not null, the orElse function will still execute the createUser() method, while the orElseGet function will not execute the createUser() method , you can test it yourself.

As for orElseThrow, when the value is null, an exception is thrown directly. The usage is as follows

User user = null;
Optional.ofNullable(user).orElseThrow(()->new Exception("User does not exist"));

3, map(Function mapper) and flatMap(Function> mapper)

These two functions are placed in a set of memory, and these two functions do the operation of converting values.

Go directly to the source code

public final class Optional<T> {
    //Omit....
     public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects. requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Optional.ofNullable(mapper.apply(value));
        }
    }
    //Omit...
     public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
        Objects. requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Objects.requireNonNull(mapper.apply(value));
        }
    }
}

There is no difference between these two functions in the function body. The only difference is the input parameter. The input parameter type accepted by the map function is Function, while the input parameter type of flapMap is Function>.

In terms of specific usage, for map:

If the User structure is as follows

public class User {
    private String name;
    public String getName() {
        return name;
    }
}

At this time, the way to write the name is as follows

String city = Optional.ofNullable(user).map(u->u.getName()).get();

For flatMap:

If the User structure is as follows

public class User {
    private String name;
    public Optional<String> getName() {
        return Optional.ofNullable(name);
    }
}

At this time, the way to write the name is as follows

String city = Optional.ofNullable(user).flatMap(u->u.getName()).get();

4. isPresent() and ifPresent(Consumer consumer)

These two functions are memorized together, isPresent is to judge whether the value is empty, and ifPresent is to do some operations when the value is not empty. The source code of these two functions is as follows

public final class Optional<T> {
    //Omit....
    public boolean isPresent() {
        return value != null;
    }
    //Omit...
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer. accept(value);
    }
}

What needs to be added is that you must not put

if (user != null){
   // TODO: do something
}

to write as

User user = Optional.ofNullable(user);
if (Optional. isPresent()){
   // TODO: do something
}

Because of this, the code structure is still ugly. The blogger will give the correct spelling later

As for ifPresent(Consumer consumer), the usage is also very simple, as shown below

Optional.ofNullable(user).ifPresent(u->{
    // TODO: do something
});

5. filter(Predicate predicate)

Not much to say, go directly to the source code

public final class Optional<T> {
    //Omit....
   Objects. requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
}

The filter method accepts a Predicate to filter the value contained in Optional, if the contained value meets the condition, then return this Optional; otherwise return Optional.empty .

The usage is as follows

Optional<User> user1 = Optional.ofNullable(user).filter(u -> u.getName().length()<6);

As shown above, if the length of the user’s name is less than 6, return it. If it is greater than 6, an EMPTY object is returned.

Background management system + user applet based on Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & amp; Element, supporting RBAC dynamic permissions, multi-tenancy, data permissions, workflow, three-party login, payment, SMS, mall and other functions

  • Project address: https://github.com/YunaiV/yudao-cloud

  • Video tutorial: https://doc.iocoder.cn/video/

Practical use

Example 1

in the function method

Previously written

public String getCity(User user) throws Exception{
        if(user!=null){
            if(user. getAddress()!=null){
                Address address = user. getAddress();
                if(address. getCity()!=null){
                    return address. getCity();
                }
            }
        }
        throw new Excpetion("Wrong value");
    }

JAVA8 writing method

public String getCity(User user) throws Exception{
    return Optional.ofNullable(user)
                   .map(u->u.getAddress())
                   .map(a->a.getCity())
                   .orElseThrow(()->new Exception("Instruction fetch error"));
}

Example 2

For example, in the main program

Previously written

if(user!=null){
    dosomething(user);
}

JAVA8 writing method

Optional.ofNullable(user)
    .ifPresent(u->{
        dosomething(u);
});

Example three

Previously written

public User getUser(User user) throws Exception{
    if(user!=null){
        String name = user. getName();
        if("zhangsan".equals(name)){
            return user;
        }
    }else{
        user = new User();
        user.setName("zhangsan");
        return user;
    }
}

Java8 writing method

public User getUser(User user) {
    return Optional.ofNullable(user)
                   .filter(u->"zhangsan".equals(u.getName()))
                   .orElseGet(() -> {
                        User user1 = new User();
                        user1.setName("zhangsan");
                        return user1;
                   });
}

Other examples are not listed one by one. However, with this kind of chain programming, although the code is elegant. However, the logic is not so obvious, and the readability has been reduced. You can use it according to the situation in your project.

Welcome to join my knowledge planet, discuss architecture and exchange source code together. How to join, Long press the QR code below:

e0c5dd0f9934fcc9367d6706d2e1752c.png

The source code has been updated on Knowledge Planet and the analysis is as follows:

b71f64e06f1e161bcf647f1dbbdf2081.jpeg

901dd5e94459efa696112e465a7835b3.jpeg

ab7a80ffa22ee5c7416a363da56ce641.jpeg

be9b209ade69f37f39dd04d43a155ea4.jpeg

The recently updated series “Introduction to Taro SpringBoot 2.X” has more than 101 articles, covering MyBatis, Redis, MongoDB, ES, sub-database and sub-table, read-write separation, SpringMVC, Webflux, permissions, WebSocket, Dubbo, RabbitMQ, RocketMQ , Kafka, performance testing, etc.

Provides a SpringBoot example with nearly 3W lines of code, and an e-commerce microservice project with more than 6W lines of code.

How to get it: Click “Looking“, follow the official account and reply to 666 to receive, more content will be provided one after another.

If the article is helpful, please read it and forward it.
Thank you for your support (*^__^*)

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge Java skill tree Optional Consistency 118,508 people are studying systematically