Java 8 in-depth study
1、 Using the optional introduction
1.1. Code problem derivation
NullPointerException is usually encountered when writing programs, so it is often judged that the program is not empty:
User user = getUserById(id); if (user != null) { String username = user.getUsername(); System.out.println("Username is: " + username); // 使用 username }
In order to solve this embarrassing situation, JDK finally added the optional class in java8. Check the Javadoc introduction of optional:
This is a container that can contain or not contain non null values. If the value exists, the ispresent () method will return true, and calling the get () method will return the object.
1.2. Advanced solutions
Assuming that getuserbyid is an objective and unchangeable method, we can write the following code by using ispresent and get methods:
Optional<User> user = Optional.ofNullable(getUserById(id)); if (user.isPresent()) { String username = user.get().getUsername(); System.out.println("Username is: " + username); // 使用 username }
It seems that the code is a little beautiful, but in fact, it is not fundamentally different from the previous code for judging null value. Instead, it uses optional to encapsulate value, which increases the amount of code. So let's take a look at what other methods optional provides to make us better (in the right posture) use optional.
2、 Optional three static construction methods
1) Overview:
JDK provides three static methods to construct an optional:
1、Optional. of(T value)
public static <T> Optional<T> of(T value) { return new Optional<>(value); }
This method constructs an option through a non null value, and the returned option contains the value. For this method, the passed in parameter must not be null, otherwise NullPointerException will be thrown.
2、Optional. ofNullable(T value)
public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); }
The difference between this method and the of method is that the parameters passed in can be null -- but didn't Javadoc say that optional can only contain non null values? We can look at the source code of ofnullable method.
Originally, this method will judge whether the passed in parameter is null. If it is null, it will return optional empty()。
3、Optional. empty()
public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }
This method is used to construct an empty option, that is, the option does not contain a value - in fact, the underlying implementation is that if the value in the option is null, the option is in a state that does not contain a value, and then the option cannot contain a null value at the API level, so that the option has only two states: containing a value and not containing a value.
2) Analysis:
As mentioned in Javadoc earlier, the ispresent () method of option is used to determine whether the value is included, and the get () method is used to obtain the value contained in option -- it is worth noting that if the value does not exist, it is in an option When the get () method is called on empty, a NoSuchElementException exception will be thrown.
3) Summary:
1)Optional. Of (obj): it requires that the incoming obj cannot be null, otherwise it will fall on the NullPointerException exception before entering the role
2)Optional. Ofnullable (obj): it constructs an optional instance in an intelligent and tolerant way If you don't refuse, you can get optional Empty(), call optional if it is not null of(obj).
Is that all we have to do is use optional Ofnullable (obj) once and for all, just construct an optional instance in the way of invariance and two variables? Not necessarily, otherwise optional Of (obj) why is it so exposed? Private can.
3、 Detailed explanation of common methods of optional
3.1 overview of common methods of optional
Optional. of(T t)
The specified value is returned after being encapsulated with optional. If the value is null, a NullPointerException exception will be thrown.
Optional. empty()
Create an empty optional instance.
Optional. ofNullable(T t)
The specified value is returned after being encapsulated with optional. If the value is null, an empty optional object is returned.
isPresent
Returns true if the value exists; otherwise, returns false
ifPresent
If the optional instance has a value, call consumer for it, otherwise it will not be processed. To understand the ifpresent method, you first need to understand the consumer class. In short, the consumer class contains an abstract method. The abstract method processes the incoming value but does not return a value. Java 8 supports passing parameters directly through lambda expressions without interfaces. If the optional instance has a value, calling ifpresent () can accept interface segments or lambda expressions.
Optional. get()
If the value exists, it will be returned in optional encapsulation, otherwise a NoSuchElementException exception will be thrown.
orElse(T t)
If the calling object contains a value, return the value; otherwise, return t.
orElseGet(supplier s)
If the calling object contains a value, return the value; otherwise, return the value obtained by S.
orElseThrow()
It throws an exception when the object is empty.
map(Function f)
If the value exists, the provided mapping function call is performed on the value.
flatMap(Function mapper)
If the value exists, execute the provided mapping function call on the value to return an optional value; otherwise, return an empty optional object.
3.2 detailed explanation of common methods of optional
3.2. 1、ifPresent
public void ifPresent(Consumer<? super T> consumer) { if (value != null) consumer.accept(value); }
If there is a value in optional, consumer. Is called on the value Accept, or do nothing. Therefore, the example in the introduction can be modified as follows:
Optional<User> user = Optional.ofNullable(getUserById(id)); user.ifPresent(u -> System.out.println("Username is: " + u.getUsername()));
3.2. 2、orElse
public T orElse(T other) { return value != null ? value : other; }
If there is a value in optional, return it; otherwise, return the parameter passed in by orelse method.
User user = Optional .ofNullable(getUserById(id)) .orElse(new User(0,"UnkNown")); System.out.println("Username is: " + user.getUsername());
3.2. 3、orElseGet
public T orElseGet(supplier<? extends T> other) { return value != null ? value : other.get(); }
The difference between orelseget and orelse methods is that the parameter passed in by orelseget method is the implementation of a supplier interface - when there is a value in optional, the return value; When there is no value in optional, the value obtained from the supplier is returned.
User user = Optional .ofNullable(getUserById(id)) .orElseGet(() -> new User(0,"UnkNown")); System.out.println("Username is: " + user.getUsername());
3.2. 4、orElseThrow
public <X extends Throwable> T orElseThrow(supplier<? extends X> exceptionsupplier) throws X { if (value != null) { return value; } else { throw exceptionsupplier.get(); } }
The difference between orelsethrow and orelse methods is that the orelsethrow method returns a value when there is a value in option; When there is no value, an exception will be thrown, which is provided by the passed in exceptionsupplier.
For example:
In the controller of spring MVC, we can configure to handle all kinds of exceptions uniformly. When querying an entity, if there is a corresponding record in the database, the record will be returned. Otherwise, an entitynotfoundexception can be thrown. In the method of handling entitynotfoundexception, we will return the HTTP status code 404 and the information corresponding to the exception to the client - orelsethrow is perfect for this scenario.
@RequestMapping("/{id}") public User getUser(@PathVariable Integer id) { Optional<User> user = userService.getUserById(id); return user.orElseThrow(() -> new EntityNotFoundException("id 为 " + id + " 的用户不存在")); } @ExceptionHandler(EntityNotFoundException.class) public ResponseEntity<String> handleException(EntityNotFoundException ex) { return new ResponseEntity<>(ex.getMessage(),HttpStatus.NOT_FOUND); }
3.2. 5、map
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)); } }
If the current option is optional Empty, it still returns optional empty; Otherwise, a new option is returned, which contains the output value of the function mapper when taking value as the input.
String username = Optional.ofNullable(getUserById(id)) .map(user -> user.getUsername()) .orElse("UnkNown") .ifPresent(name -> System.out.println("Username is: " + name));
Moreover, we can use map operations multiple times:
Optional<String> username = Optional.ofNullable(getUserById(id)) .map(user -> user.getUsername()) .map(name -> name.toLowerCase()) .map(name -> name.replace('_',' ')) .orElse("UnkNown") .ifPresent(name -> System.out.println("Username is: " + name));
3.2. 6、flatMap
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)); } }
The difference between the flatmap method and the map method is that the function mapper in the map method parameter outputs a value, and then the map method uses optional Ofnullable packages it as optional; Flatmap requires that the function mapper in the parameter output is optional.
Optional<String> username = Optional.ofNullable(getUserById(id)) .flatMap(user -> Optional.of(user.getUsername())) .flatMap(name -> Optional.of(name.toLowerCase())) .orElse("UnkNown") .ifPresent(name -> System.out.println("Username is: " + name));
3.2. 7、filter
public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); }
The filter method accepts a predicate to filter the values contained in the optional. If the contained values meet the conditions, the optional is returned; Otherwise, it returns optional empty。
Optional<String> username = Optional.ofNullable(getUserById(id)) .filter(user -> user.getId() < 10) .map(user -> user.getUsername()); .orElse("UnkNown") .ifPresent(name -> System.out.println("Username is: " + name));
4、 Optional usage example
4.1 use display I
When user If ispresent() is true, the mapped set of its associated orders will be obtained. If it is false, an empty set will be returned. When the orelse and orelseget methods above are weak, it is originally the responsibility of the map function. We can:
return user.map(u -> u.getOrders()).orElse(Collections.emptyList()) //上面避免了我们类似 Java 8 之前的做法 if(user.isPresent()) { return user.get().getOrders(); } else { return Collections.emptyList(); }
The map can be cascaded infinitely. For example, go deeper and get the uppercase form of the user name:
return user.map(u -> u.getUsername()) .map(name -> name.toUpperCase()) .orElse(null);
Previous practice:
User user = ..... if(user != null) { String name = user.getUsername(); if(name != null) { return name.toUpperCase(); } else { return null; } } else { return null; }
Filter (): if there is a value and the conditions are met, the optional containing the value is returned; otherwise, the null option is returned.
Optional<String> longName = name.filter((value) -> value.length() > 6); System.out.println(longName.orElse("The name is less than 6 characters"));
summary
The above is the whole content of this article. I hope the content of this article has a certain reference value for your study or work. Thank you for your support.