JDK 1.8 Optional使用技巧
一、 Optional 构造方法
JDK提供了三个静态方法来构造一个Optional。
1.1 Optional.empty()
Optional.empty(),该方法用来构造一个空的Optional。即Optional里面不好看
1.2 Optional.of()
Optional.of(T value),该方法通过传入一个非null的value来构造一个Optional,返回Optional包含了value这个值。对于该方法,传入的参数一定不为空,否则会抛出NullPointerException
。
1.3Optional.ofNullable()
Optional.ofNullable(T value),该方法和of方法的区别在于,传入的参数可以为null。当传入参数为null时,就会返回Optional.empty()。
2. Optional相关方法
2.1 isPresent
判断是否引用缺失可以使用optional.isPresent();
,底层使用if(xxx== null),返回boolean值。不推荐使用。
2.2 ifPresent
如果Optional中有值,则对该值调用consumer.accept,否则什么也不做。
Optional<Object> optional = Optional.ofNullable("zhangsan");
//打印optional传入的对象
optional.ifPresent(System.out::println);
2.2 orElse
如果Optional有值,则将其返回,否则返回orElse()方法传入的参数。
User user = Optional
.ofNullable(getUserById(id))
.orElse(new User(0,"Unknown User"))
System.out.println("Username is: " + user.getUsername());
2.3 orElseGet
orElseGet和orElse的方法区别在于,orElseGet方法传入的参数为一个super接口的实现。当Optional有值时,返回值。当Optional中没有值的时候,返回从该Suppiler获得值。
User user = Optional
.ofNullable(getUserById(id))
.orElseGet(() -> new User(0, "Unknown"));
System.out.println("Username is: " + user.getUsername());
2.4 orElseThrow
orElseThrow与orElse方法的区别在于,orElseThrow方法当Optional中有值的时候,返回值,没有的时候抛出异常,抛出的异常由传入的exceptionSuppiler提供。
User user = Optional
.ofNullable(getUserById(id))
.orElseThrow(() -> new EntityNotFoundException("id 为 " + id + " 的用户没有找到"));
2.5 map
当optional为空的时候,返回empty(),否则返回一个新的Optional,该Optional包装的是mapper以value做出输入的输出值。
2.6 flatMap
flatMap和map方法的区别是,map方法参数中的mapper输出的是值,map方法会使用Optional.ofNullable将其包装成optional,而flatMap要求参数中的mapper输出的就是Optional。
2.7 filter
filter方法接收一个Predicate来对Optional中包含的值进行过滤,如果包含的值满足条件,那么还是返回这个Optional;否则返回Optional.empty
Optional<String> username = Optional
.ofNullable(getUserById(id))
.filter(user -> user.getId() < 10)
.map(user -> user.getUsername());
System.out.println("Username is: " + username.orElse("Unknown"));
有了Optional,可以方便且优雅的在代码中处理null值,而不是需要通过if(Object!=null)来判断值是否为空,如果JDK1.8版本以前,可以考虑使用google的guava库,早在JDK 的年代,Guava就提供了Optional的实现。
3. 综合案例
@Data
public class SkuVO {
private Long skuId;
private Price price;
}
@Data
public class Price {
private BigDecimal mallPrice;
private BigDecimal sellPrice;
}
有一个SkuVO对象,里面包含了一个skuId和一个price对象,price对象里面有市场价和成本价。假设有需求获取sku里面的mallPrice并返回。按照jdk 1.8以前的思路一般这么写
private static BigDecimal fetchMallPrice1(SkuVO skuVO) throws Exception {
if (skuVO != null) {
Price price = skuVO.getPrice();
if (price != null) {
BigDecimal mallPrice = price.getMallPrice();
if (mallPrice != null) {
if (mallPrice.compareTo(new BigDecimal("10")) == 1) {
return mallPrice;
}
}
}
}
在真实的项目中,这样的写法实在是太常见了。各种非空判断才敢继续执行,否则会抛出NullPointerException
,但是这样的代码,if嵌套太深,可读性非常差。
JDK 1.8的写法可以改造为
private static BigDecimal fetchMallPrice2(SkuVO skuVO)throws Exception{
return Optional.ofNullable(skuVO)
.map(s->s.getPrice())
.map(p -> p.getMallPrice())
.filter(m -> m.compareTo(new BigDecimal(10)) ==1)
.orElse(new BigDecimal(10));
}
Optional.ofNullable(skuVO)首先构造一个Optional,map(Function<? super T, ? extends U> mapper)接收一个Funtion,filter过滤map返回的值,最后通过orElseThrow抛出异常。