The introduction

At the beginning of this 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 whose UML class diagrams are shown belowIn this case, there is the following code

user.getAddress().getProvince();
Copy the code

If user is null, NullPointerException may be reported. To solve this problem, the following is used

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

This writing method is ugly, in order to avoid the ugly writing method, let the ugly design become elegant. JAVA8 provides the Optional class to optimize this writing, which is explained in the following text

The API is introduced

Let’s start with the API. Unlike other articles, this article takes an analogy approach and combines the source code. Unlike other articles, API listed one by one, people can not find the focus.

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

These four functions are related to each other and are therefore memorized as a group.

The Optional(T value) constructor is private and cannot be called externally. The remaining three functions are public permissions for us to call.

So Optional essentially stores a real value, and when you construct it, you can tell if it’s null. Okay, that’s a bit abstract. Go directly to the Optional(T value) constructor source, as shown below

So, the source of of(T value) is as follows

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

That is, the constructor is called inside the of(T value) function. Based on the constructor source, we can draw two conclusions:

  • An Optional object constructed from the of(T value) function will still report a NullPointerException if value is null.
  • The Optional object is constructed by using the of(T value) function. If the value is not empty, the Optional object can be constructed.

In addition, the Optional class also maintains an object with a value of null, something like this

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; }}Copy the code

So empty () returns an empty object.

Good foreshadowing so much, can say ofNullable(T value) of the role of the source code

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

Okay, I think you get the idea. When the value of(T value) is null, a NullPointerException is raised. OfNullable (T value) does not throw Exception. OfNullable (T value) returns an EMPTY object.

Does that mean we use ofNullable instead of of in our project?

No, a thing exists naturally and deserves to exist. We don’t want to hide NullPointerException while we’re running. You want to report it immediately, in which case you use the Of function. But I have to admit, these scenes are really rare. Bloggers have only used this function in writing junit test cases.

2, orElse(T other), orElseGet(Supplier<? Extends T> other) and orElseThrow(Supplier<? extends X> exceptionSupplier)

All three functions are called when the value passed in by the constructor is null. OrElse and orElseGet are used as follows, which is equivalent to giving a default value when 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;
}
Copy the code

When user is not null, orElse will still execute createUser(). OrElseGet will not execute createUser().

If value is null, throw an exception as shown below

User user = null; Option.ofnullable (user).orelsethrow (()->new Exception(" user does not exist "));Copy the code

3, the map (the Function <? super T, ? Extends U> mapper) and flatMap(Function<? super T, Optional> mapper)

These two functions are grouped together in memory, and these two functions do the conversion operation.

Direct 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)); }}}Copy the code

There’s no difference in the body between these two functions. The only difference is that the map Function accepts an input parameter of type Function<? super T, ? Extends U>, while flapMap has an input type of Function<? Super T, Optional >.

In terms of specific usage, for map:

If the User structure looks like this

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

In this case, name is written as follows

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

For flatMap:

If the User structure looks like this

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

In this case, name is written as follows

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

4, isPresent() and ifPresent(Consumer<? super T> consumer)

So these two functions put together, isPresent is to check if value is null, and ifPresent is to do something if value is not null. The source code for these two functions is shown below

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); }}Copy the code

It should be added that you should not

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

Give written

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

Because of this, the code structure is still ugly. The blogger will give you the correct way to write it later

As for ifPresent (Consumer <? Super T> consumer), the usage is also simple, as shown below

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

5, the filter (Predicate <? super T> predicate)

Don’t say much, directly on the source code

Public final class Optional<T> {// omit.... Objects.requireNonNull(predicate); if (! isPresent()) return this; else return predicate.test(value) ? this : empty(); }Copy the code

The filter method accepts Predicate to filter the values contained in the Optional, and returns the Optional if the values meet the criteria. Otherwise return Optional. Empty.

Use the following

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

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

Practical use

Patients with a

In the function method

Before writing

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(" error "); }Copy the code

JAVA8 writing

public String getCity(User user) throws Exception{ return Optional.ofNullable(user) .map(u-> u.getAddress()) . The map (a - > al-qeada etCity ()). OrElseThrow (() - > new Exception (" refers to the error ")); }Copy the code

Example 2

For example, in the main program

Before writing

if(user! =null){ dosomething(user); }Copy the code

JAVA8 writing

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

Example 3

Before writing

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;
    }
}
Copy the code

Java8 writing

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;
                   });
}
Copy the code

Other examples are not listed. But with this kind of chained programming, the code is elegant. However, the logic is not so obvious, the readability is reduced, you see the situation of the project as appropriate to use.

Author: zjhred blog.csdn.net/zjhred/article/details/84976734