premise
java.util.Optional
JDK8 is introduced in class, which is famous JDK from Java toolkit Guava
ported in. Use the time of this writing is JDK11. Optional
Contains a NULL
value or a non- NULL
object container values, it is often used as clear that no result (in fact clearly indicates that there may also be a result of Optional
representation) method return types, avoid NULL
value possible anomalies caused by (usually NullPointerException
). That is, the method returns a value of type is Optional
, you should avoid returning NULL
, but should make a point to return value contains the NULL
object Optional
instance. Optional
The emergence of NULL
judgment, the filtering operation, a mapping operation provides a functional adaptation entrance, be it an important milestone Java introduced functional programming.
In this paper a new Asciidoc
preview mode, you can experience Spring
the feeling of the official document:
- Github Page:www.throwable.club/adoc/201908…
- Coding Page:throwable.coding.me/adoc/201908…
Optional various methods and use source code analysis scenarios
Optional
The source code is relatively simple, it is rooted in a simple object container. The following analysis will combine all of its source structure, properties, methods, and use of the corresponding scene.
Optional property and construction
Optional
Properties and constructed as follows:
public final class Optional<T> {
// 这个是通用的代表NULL值的Optional实例
private static final Optional<?> EMPTY = new Optional<>();
// 泛型类型的对象实例
private final T value;
// 实例化Optional,注意是私有修饰符,value置为NULL
private Optional() {
this.value = null;
}
// 直接返回内部的EMPTY实例
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
// 通过value实例化Optional,如果value为NULL则抛出NPE
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
// 通过value实例化Optional,如果value为NULL则抛出NPE,实际上就是使用Optional(T value)
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
// 如果value为NULL则返回EMPTY实例,否则调用Optional#of(value)
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
// 暂时省略其他代码
}
复制代码
If an object instance is not clear NULL
, you should use Optional#of()
, for example:
Order o = selectByOrderId(orderId);
assert null != o
Optional op = Optional.of(o);
复制代码
If you can not clear an object instance is NULL
when you should use Optional#ofNullable()
, for example:
Optional op = Optional.ofNullable(selectByOrderId(orderId));
复制代码
Made it clear that holds a NULL
value of Optional
instances can use Optional.empty()
.
get () method
// 如果value为空,则抛出NPE,否则直接返回value
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
复制代码
get()
The method generally need to be clear value
is not NULL
the time to use it to do a priori value
existence. E.g:
Order o = selectByOrderId(orderId);
assert null != o
Optional op = Optional.of(o);
Order value = op.get();
复制代码
isPresent () method
// 判断value是否存在,不为NULL则返回true,如果为NULL则返回false
public boolean isPresent() {
return value != null;
}
复制代码
for example:
Order o = selectByOrderId(orderId);
boolean existed = Optional.ofNullable(o).isPresent();
复制代码
isEmpty () method
isEmpty()
JDK11 method is introduced, a isPresent()
reverse determination:
// 判断value是否存在,为NULL则返回true,为非NULL则返回false
public boolean isEmpty() {
return value == null;
}
复制代码
ifPresent () method
ifPresent()
Action approach is: If value
not NULL
, use the value
consumer interface method calls a function of consumers Consumer#accept()
:
public void ifPresent(Consumer<? super T> action) {
if (value != null) {
action.accept(value);
}
}
复制代码
E.g:
Optional.ofNullable(selectByOrderId(orderId)).ifPresent(o-> LOGGER.info("订单ID:{}",o.getOrderId());
复制代码
ifPresentOrElse () method
ifPresentOrElse()
The method is JDK9 new method, which is ifPresent()
an enhanced version of the method, if value
not NULL
, use the value
consumer interface method calls a function of consumers Consumer#accept()
, if value
to NULL
execute Runnable#run()
:
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
if (value != null) {
action.accept(value);
} else {
emptyAction.run();
}
}
复制代码
E.g:
String orderId = "xxxx";
Optional.ofNullable(selectByOrderId(orderId)).ifPresentOrElse(o-> LOGGER.info("订单ID:{}",o.getOrderId()), ()-> LOGGER.info("订单{}不存在",o.getOrderId()));
复制代码
filter () method
public Optional<T> filter(Predicate<? super T> predicate) {
// 判断predicate不能为NULL
Objects.requireNonNull(predicate);
// value为NULL,说明是空实例,则直接返回自身
if (!isPresent()) {
return this;
} else {
// value不为NULL,则通过predicate判断,命中返回自身,不命中则返回空实例empty
return predicate.test(value) ? this : empty();
}
}
复制代码
This function is a simple method of filtering, the container holding the object value
non NULL
'll do a judge, he decided to return to their own instance or empty()
. E.g:
Optional.ofNullable(selectByOrderId(orderId)).filter(o -> o.getStatus() == 1).ifPresent(o-> LOGGER.info("订单{}的状态为1",o.getOrderId));
复制代码
map () method
map()
Value map is a simple operation:
public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
// 判断mapper不能为NULL
Objects.requireNonNull(mapper);
// value为NULL,说明是空实例,则直接返回empty()
if (!isPresent()) {
return empty();
} else {
// value不为NULL,通过mapper转换类型,重新封装为可空的Optional实例
return Optional.ofNullable(mapper.apply(value));
}
}
复制代码
An example API annotation inside:
List<URI> uris = ...;
// 找到URI列表中未处理的URI对应的路径
Optional<Path> p = uris.stream().filter(uri -> !isProcessedYet(uri)).findFirst().map(Paths::get);
复制代码
flatMap () method
flatMap()
The method is a mapping operation, but the mapping Optional
type of the return value is determined directly from the outside without going through the reseal value Optional
Example:
public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
// mapper存在性判断
Objects.requireNonNull(mapper);
// value为NULL,说明是空实例,则直接返回empty()
if (!isPresent()) {
return empty();
} else {
// value不为NULL,通过mapper转换,直接返回mapper的返回值,做一次空判断
@SuppressWarnings("unchecked")
Optional<U> r = (Optional<U>) mapper.apply(value);
return Objects.requireNonNull(r);
}
}
复制代码
E.g:
class OptionalOrderFactory{
static Optional<Order> create(String id){
//省略...
}
}
String orderId = "xxx";
Optional<Order> op = Optional.of(orderId).flatMap(id -> OptionalOrderFactory.create(id));
复制代码
or () method
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
// supplier存在性判断
Objects.requireNonNull(supplier);
// value不为NULL,则直接返回自身
if (isPresent()) {
return this;
} else {
// value为NULL,则返回supplier提供的Optional实例,做一次空判断
@SuppressWarnings("unchecked")
Optional<T> r = (Optional<T>) supplier.get();
return Objects.requireNonNull(r);
}
}
复制代码
E.g:
Order a = null;
Order b = select();
// 拿到的就是b订单实例包装的Optional
Optional<Order> op = Optional.ofNullable(a).or(b);
复制代码
stream () method
// 对value做NULL判断,转换为Stream类型
public Stream<T> stream() {
if (!isPresent()) {
return Stream.empty();
} else {
return Stream.of(value);
}
}
复制代码
orElse () method
// 值不为NULL则直接返回value,否则返回other
public T orElse(T other) {
return value != null ? value : other;
}
复制代码
orElse()
Is a common method to provide default values reveal all the details, such as:
String v1 = null;
String v2 = "default";
// 拿到的就是v2对应的"default"值
String value = Optional.ofNullable(v1).orElse(v2);
复制代码
orElseGet () method
// 值不为NULL则直接返回value,否则返回Supplier#get()
public T orElseGet(Supplier<? extends T> supplier) {
return value != null ? value : supplier.get();
}
复制代码
orElseGet()
Only orElse()
method an upgraded version, for example:
String v1 = null;
Supplier<String> v2 = () -> "default";
// 拿到的就是v2对应的"default"值
String value = Optional.ofNullable(v1).orElseGet(v2);
复制代码
orElseThrow () method
// 如果值为NULL,则抛出NoSuchElementException,否则直接返回value
public T orElseThrow() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
// 如果值不为NULL,则直接返回value,否则返回Supplier#get()提供的异常实例
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
复制代码
E.g:
Optional.ofNullable(orderInfoVo.getAmount()).orElseThrow(()-> new IllegalArgumentException(String.format("%s订单的amount不能为NULL",orderInfoVo.getOrderId())));
复制代码
equals () and hashCode () method
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Optional)) {
return false;
}
Optional<?> other = (Optional<?>) obj;
return Objects.equals(value, other.value);
}
public int hashCode() {
return Objects.hashCode(value);
}
复制代码
Comparison of these two methods are value
described of Optional
example, if used in HashMap
the KEY, as long as value
the same, for HashMap
that same KEY. Such as:
Map<Optional,Boolean> map = new HashMap<>();
Optional<String> op1 = Optional.of("throwable");
map.put(op1, true);
Optional<String> op2 = Optional.of("throwable");
map.put(op2, false);
// 输出false
System.out.println(map.get(op1));
复制代码
Optional combat
The following show how Optional
some common usage scenarios.
Empty judgment
Empty judgment is mainly used do not know whether the current object is NULL
when you need to set properties of the object. Not used Optional
when the code is as follows:
if(null != order){
order.setAmount(orderInfoVo.getAmount());
}
复制代码
Using Optional
the time code is as follows:
Optional.ofNullable(order).ifPresent(o -> o.setAmount(orderInfoVo.getAmount()));
// 如果判断空的对象是OrderInfoVo如下
Order o = select();
OrderInfoVo vo = ...
Optional.ofNullable(vo).ifPresent(v -> o.setAmount(v.getAmount()));
复制代码
Use Optional
the benefits of empty judgment is achieved only when a property value set can be compressed into one line of code to do so, the code will be relatively simple.
Affirmation
In the maintenance of some old system, when an external mass participation in many cases there is no short judgment, it is necessary to write some code that assertions such as:
if (null == orderInfoVo.getAmount()){
throw new IllegalArgumentException(String.format("%s订单的amount不能为NULL",orderInfoVo.getOrderId()));
}
if (StringUtils.isBlank(orderInfoVo.getAddress()){
throw new IllegalArgumentException(String.format("%s订单的address不能为空",orderInfoVo.getOrderId()));
}
复制代码
Using Optional
the assertion code is as follows:
Optional.ofNullable(orderInfoVo.getAmount()).orElseThrow(()-> new IllegalArgumentException(String.format("%s订单的amount不能为NULL",orderInfoVo.getOrderId())));
Optional.ofNullable(orderInfoVo.getAddress()).orElseThrow(()-> new IllegalArgumentException(String.format("%s订单的address不能为空",orderInfoVo.getOrderId())));
复制代码
Integrated Simulation Case
The following is a simulation case, the step of simulation are as follows:
- Gives the customer ID list query list of customers.
- Check your order list based on the list of clients that exist in the customer ID.
- Converted to an order DTO view the list based on the order list.
@Data
static class Customer {
private Long id;
}
@Data
static class Order {
private Long id;
private String orderId;
private Long customerId;
}
@Data
static class OrderDto {
private String orderId;
}
// 模拟客户查询
private static List<Customer> selectCustomers(List<Long> ids) {
return null;
}
// 模拟订单查询
private static List<Order> selectOrders(List<Long> customerIds) {
return null;
}
// main方法
public static void main(String[] args) throws Exception {
List<Long> ids = new ArrayList<>();
List<OrderDto> view = Optional.ofNullable(selectCustomers(ids))
.filter(cs -> !cs.isEmpty())
.map(cs -> selectOrders(cs.stream().map(Customer::getId).collect(Collectors.toList())))
.map(orders -> {
List<OrderDto> dtoList = new ArrayList<>();
orders.forEach(o -> {
OrderDto dto = new OrderDto();
dto.setOrderId(o.getOrderId());
dtoList.add(dto);
});
return dtoList;
}).orElse(Collections.emptyList());
}
复制代码
summary
Optional
It is essentially an object container, which is characterized as follows:
Optional
As a container carrying an object to provide a method fitting portion interface function, binding portion provides interface functions implemented method ofNULL
determination, filtering, security values, mapping operations and so on.Optional
Scenario is typically used for packaging method returns a value, of course, also be used as temporary variables and thus enjoy convenient functional interfaces.Optional
Just a tool to simplify the operation, not a silver bullet, there are many problems can not be solved substantive encoding, such as an arrow type code issues.
Arrow type the code mentioned here, try the following conventional methods and Optional
are resolved (no substantive change, but the introduction of a higher code complexity):
// 假设VO有多个层级,每个层级都不知道父节点是否为NULL,如下
// - OrderInfoVo
// - UserInfoVo
// - AddressInfoVo
// - address(属性)
// 假设我要为address属性赋值,那么就会产生箭头型代码。
// 常规方法
String address = "xxx";
OrderInfoVo o = ...;
if(null != o){
UserInfoVo uiv = o.getUserInfoVo();
if (null != uiv){
AddressInfoVo aiv = uiv.getAddressInfoVo();
if (null != aiv){
aiv.setAddress(address);
}
}
}
// 使用Optional
String address = "xxx";
OrderInfoVo o = ...;
Optional.ofNullable(o).ifPresent(oiv-> {
Optional.ofNullable(oiv.getUserInfoVo()).ifPresent(uiv -> {
Optional.ofNullable(uiv.getAddressInfoVo()).ifPresent(aiv->{
aiv.setAddress(address);
})
})
});
复制代码
Some developers proposed the DAO
method's return value type is defined as Optional
, the author of this neutral, because:
Optional
Is JDK1.8 introduced low version of the JDK and can not be used, not all systems can smooth migration to JDK1.8 +.- Not everyone is keen on functional programming, because it brings convenience at the same time changed the logic of reading the code (some people even think that reduces the readability of the code).
annex
- Github Page:www.throwable.club/2019/08/07/…
- Coding Page:throwable.coding.me/2019/08/07/…
- Markdown or Asciidoc file: github.com/zjcscut/blo...
(End herein, c-2-d ea-20190805 by throwable)