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