How to use the Optional API for JDK8 series?
1, Optional brief introduction
In the previous chapter, we learned about lambada expressions, method references, functional interfaces, etc. In this blog, we continue to learn about Optional features in JDK8. Jdk8 designed this Optional option to avoid nullPointerExceptions that are common in development
Optional is a guaranteed step toward functional programming in Java and helps with implementation within the paradigm
2. Why does Optional avoid null Pointers?
Why does Optional avoid NullPointerExceptions? The following code can be found inside:
/**
* Returns an {@code Optional} describing the specified value, if non-null,
* otherwise returns an empty {@code Optional}.
*
* @param <T> the class of the value
* @param value the possibly-null value to describe
* @return an {@code Optional} with a present value if the specified value
* is non-null, otherwise an empty {@code Optional}
*/
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
/ /...
public static<T> Optional<T> empty(a) {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
Copy the code
If value is null, return empty() as an Optional object. New Optional<>()
/**
* Common instance for {@code empty()}.
*/
private static finalOptional<? > EMPTY =new Optional<>();
Copy the code
And the other method is option.of (),
/**
* Returns an {@code Optional} with the specified present non-null value.
*
* @param <T> the class of the value
* @param value the value to be present, which must be non-null
* @return an {@code Optional} with the value present
* @throws NullPointerException if value is null
*/
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
Copy the code
Next, we can see that if T value is passed null, the null pointer is still abnormal
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
Copy the code
3. Create an Optional instance
- Create an empty Optional using the empty() method.
// Create an empty Optional using the empty() method
Optional<User> empOpt = Optional.empty();
empOpt.get();
Copy the code
- Use the of() method to create an Optional value that contains the value. You cannot pass in a null value
User user = new User();
Optional<User> opt = Optional.of(user);
Copy the code
- Use the ofNullable() method to create an Optional containing the value, passing in a null value
User userObj = null;
Optional<User> userOptional = Optional.ofNullable(userObj);
Copy the code
4. Access the value of the Optional object
Get the value of the Optional object using the get() method
String name = "jack";
Optional<String> strOpt = Optional.ofNullable(name);
String getStr = strOpt.get();
System.out.println(getStr);
Copy the code
Seems to be very normal, if passing a null values, will throw exceptions Java. Util. NoSuchElementException: No value the present, so you need to use ifPresent, avoid the userInfo value is null
City city = new City("Shanghai");
Address address = new Address("200000",city);
User userInfo = new User("jack"."15588899988" , "[email protected]", address);
Optional.ofNullable(userInfo).ifPresent(us -> System.out.println(us.toString()));
Copy the code
- IsPresent does not recommend this, and syntactically it is ok, but the designers intended to use the concise Java syntax of the Expression language
Optional<User> userOptiion = Optional.ofNullable(userInfo);
if (userOptiion.isPresent()) {
User userInfomation = userOptiion.get();
}
Copy the code
5. Optional Returns the default value
- Use orElse() to return the default, if there is a value, and default if there is no data
// Use orElse() to return the default value, if there is a value, no data return the default value
User tUser = null;
System.out.println("using orElse");
tUser = Optional.ofNullable(tUser).orElse(defaultUserInfo());
System.out.println("default user information:"+tUser.toString());
Copy the code
- Return the default value using orElseGet(). This method returns a value if there is one, and if there is no value, it executes the Supplier functional interface passed in as an argument
User teUser = null;
System.out.println("using orElseGet");
teUser = Optional.ofNullable(teUser).orElseGet(() -> defaultUserInfo());
System.out.println("default user information:"+teUser.toString());
Copy the code
DefaultUserInfo, returns default user data
protected static User defaultUserInfo(a){
System.out.println("create default user information!");
City city = new City("Shanghai");
Address address = new Address("200000",city);
User userInfo = new User("jack"."15588899988" , "[email protected]", address);
return userInfo;
}
Copy the code
At first glance, they both seem to work the same way, right? What’s the difference? Or to verify by example:
If the value passed in is null, compare orElse with orElseGet
User tUser = null;
System.out.println("using orElse");
tUser = Optional.ofNullable(tUser).orElse(defaultUserInfo());
System.out.println("default user information:"+tUser.toString());
User teUser = null;
System.out.println("using orElseGet");
teUser = Optional.ofNullable(teUser).orElseGet(() -> defaultUserInfo());
System.out.println("default user information:"+teUser.toString());
Copy the code
As you can see, both orElse and orElseGet call the default method
using orElse
create default user information! using orElseGet create default user information!
If the value passed in is not null, orElse calls the default method, and orElseGet does not call the default method
User tUser = new User("jack"."15588899988" , "[email protected]", address);
System.out.println("using orElse");
tUser = Optional.ofNullable(tUser).orElse(defaultUserInfo());
System.out.println("default user information:"+tUser.toString());
User teUser = new User("jack"."15588899988" , "[email protected]", address);
System.out.println("using orElseGet");
teUser = Optional.ofNullable(teUser).orElseGet(() -> defaultUserInfo());
System.out.println("default user information:"+teUser.toString());
Copy the code
using orElse
create default user information! using orElseGet
OrElse and orElseGet call the default method if the value passed in is null. In the case that the value passed is not null, orElse calls the default method, and orElseGet does not call the default method
6. Optional returns an exception
Optional also defines the orElseThrow() API, which throws an exception when the object is empty rather than returning an alternate value
User u = null;
User userData = Optional.ofNullable(u).orElseThrow(() -> new IllegalArgumentException());
Copy the code
7, Optional conversion value
To convert data, you can use the map() method to convert Optional values
The map example:
User us = new User("tom"."15588899988" , "[email protected]".null."");
String email = Optional.ofNullable(us).map(userInfor -> userInfor.getEmail()).orElse("[email protected]");
Copy the code
If the data in the class is encapsulated with Optional, it looks like this:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.util.Optional;
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
// ...
private String position;
public Optional<String> getPosition(a) {
returnOptional.ofNullable(position); }}Copy the code
When flatMap() is used as an argument, the value returned is the unwrapped String value
String position = Optional.ofNullable(us).flatMap(use -> use.getPosition()).orElse("default");
Copy the code
8, Optional filter value
In addition to transforming values, the Optional class also provides methods to “filter” values by conditions, and filter() accepts a Predicate argument
Optional<User> uoptional = Optional.ofNullable(us).filter(euser -> euser.getEmail()! =null && euser.getEmail().contains("@"));
System.out.println(uoptional.get().toString());
Copy the code
9. A typical Optional example
A typical example of a nested call:
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
private String name;
private String mobiTel;
private String email;
private Address address;
private String position;
public Optional<String> getPosition(a) {
returnOptional.ofNullable(position); }}@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Address {
private String emailCode;
private City city;
}
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class City {
private String cityName;
}
Copy the code
Draw a diagram to show class relationships:Uml class diagram:
Jdk7 writing:
/**
* the example of jdk7 getCityName .<br>
* @Author nicky.ma
* @Date2021/07/20 my *@Param [user]
* @return java.lang.String
*/
protected static String getCityName(User user) {
if(user ! =null) {
Address address = user.getAddress();
if(address ! =null) {
City city = address.getCity();
if(city ! =null) {
returncity.getCityName(); }}}throw new IllegalArgumentException("Wrong value");
}
Copy the code
Jdk8 writing:
/**
* the example of jdk8 getCityName .<br>
* @Author nicky.ma
* @Date2021/07/20 out *@Param [user]
* @return java.lang.String
*/
protected static String obtainCityName(User user) {
return Optional.ofNullable(user)
.map(u -> u.getAddress())
.map(a -> a.getCity())
.map(c -> c.getCityName())
.orElseThrow(() -> new IllegalArgumentException("Wrong value"));
}
Copy the code
10. Appendix Reference materials
- www.runoob.com/java/java8-…
- Beginnersbook.com/2017/10/jav…
- Howtodoinjava.com/java-8-tuto…