ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] # 简介 Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。 Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。 Optional 类的引入很好的解决空指针异常。 ~~~ public final class Optional<T> extends Object ~~~ # 类结构 ## Optional属性 Optional类中包含两个属性: * 类属性:EMPTY * 对象属性:value EMPTY属性用来存放一个value为null的Optional对象。 value属性用来存放非null对象。 ## Optional方法 Optional的有两个构造方法,都被private修饰。 ~~~ private Optional() { this.value = null; } private Optional(T value) { this.value = Objects.requireNonNull(value); } ~~~ 无参构造方法用来初始化EMPTY。有参构造方法用来初始化非null对象。 因为构造方法被修饰为私有的,Optional想要实例化对象只能通过类方法调用。Optional提供三个类方法。 * empty:返回value为null的Optional对象 * of:返回value非null的Optional对象 * ofNullable:value的值根据参数是否为null返回对应的Optional对象 ~~~ public static<T> Optional<T> empty() { Optional<T> t = (Optional<T>) EMPTY; return t; } public static <T> Optional<T> of(T value) { return new Optional<>(value); } public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); } ~~~ 不得不提一下 Optional 的三种构造方式: ~~~ Optional.of(obj) , Optional.ofNullable(obj) 和明确的 Optional.empty() ~~~ Optional.of(obj) : 它要求传入的 obj 不能是 null 值的, 否则还没开始进入角色就倒在了 NullPointerException 异常上了. Optional.ofNullable(obj) : 它以一种智能的, 宽容的方式来构造一个 Optional 实例. 来者不拒, 传 null 进到就得到 Optional.empty() , 非 null 就调用 Optional.of(obj) . 那是不是我们只要用 Optional.ofNullable(obj) 一劳永逸, 以不变应二变的方式来构造 Optional 实例就行了呢? 那也未必, 否则 Optional.of(obj) 何必如此暴露呢, 私有则可? 1. 当我们非常非常的明确将要传给 Optional.of(obj) 的 obj 参数不可能为 null 时, 比如它是一个刚 new 出来的对象( Optional.of(new User(...)) ), 或者是一个非 null 常量时; 2. 当想为 obj 断言不为 null 时, 即我们想在万一 obj 为 null 立即报告 NullPointException 异常, 立即修改, 而不是隐藏空指针异常时, 我们就应该果断的用 Optional.of(obj) 来构造 Optional 实例, 而不让任何不可预计的 null 值有可乘之机隐身于 Optional 中. ## 实例方法介绍 ![](https://box.kancloud.cn/233bcdd3ab89e33701aae18f59d839f0_822x538.png) ## 常用方法 ~~~ Optional.of(T t) : 创建一个 Optional 实例 Optional.empty() : 创建一个空的 Optional 实例 Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例 isPresent() : 判断是否包含值 T get(): 如果调用对象包含值,返回该值,否则抛异常 orElse(T t) :  如果调用对象包含值,返回该值,否则返回t orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值 map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty() flatMap(Function mapper):与 map 类似,要求返回值必须是Optional ~~~ # 使用 ## empty empty方法通过工厂创建一个空的Optional. ~~~ Optional empty = Optional.empty(); ~~~ ## of of方法通过工厂方法创建Optional类 **注:创建对象时传入的参数不能为null。如果传入参数为null,则抛出NullPointerException。 ** ~~~ //调用工厂方法创建Optional实例 Optional<String> name = Optional.of("Sanaulla"); //传入参数为null,抛出NullPointerException. Optional<String> someNull = Optional.of(null); ~~~ ## ofNullable ofNullable与of方法相似,唯一的区别是可以接受参数为null的情况 ~~~ //下面创建了一个不包含任何值的Optional实例 //例如,值为'null' Optional empty = Optional.ofNullable(null) ~~~ ## 判断是否有值 isPresent用来判断Optinal是否有值。如果值存在返回true,否则返回false ~~~ Optional emptyOptional = Optional.empty(); // emptyOptional为空,打印结果为true System.out.println(emptyOptional.isPresent()); Optional<String> ofOptional = Optional.of("wang"); // ofOptional有值,打印结果为true System.out.println(ofOptional.isPresent()); ~~~ ## 应避免` if(user.isPresent()) { ... } else { ... } `几种方式 **存在即返回, 无则提供默认值** ~~~ return user.orElse(null); //而不是 return user.isPresent() ? user.get() : null; return user.orElse(UNKNOWN_USER); ~~~ **存在即返回, 无则由函数来产生** ~~~ return user.orElseGet(() -> fetchAUserFromDatabase()); //而不要 return user.isPresent() ? user: fetchAUserFromDatabase(); ~~~ **存在才对它做点什么** ~~~ user.ifPresent(System.out::println); //而不要下边那样 if (user.isPresent()) { System.out.println(user.get()); } ~~~ ## 转换Optional ### filter filter方法接受一个条件函数,对Optional进行过滤。如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。 ~~~ //filter方法检查给定的Option值是否满足某些条件。 //如果满足则返回同一个Option实例,否则返回空Optional。 Optional<Integer> age = Optional.of(20); Optional<Integer> oldAge = age.filter(a -> a > 18); Optional<Integer> lessAge = age.filter(a -> a < 18); // 打印结果:Optional[20] System.out.println(oldAge); // 打印结果:Optional.empty System.out.println(lessAge); ~~~ ### map map方法用来对Optional实例的值执行一系列操作。通过一组实现了Function接口的lambda表达式传入操作。如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。 ~~~ Optional emptyOptional = Optional.empty(); Optional<Integer> ageMap = Optional.of(20); Optional<String> ageMap_ = ageMap.map(a -> "ageMap:" + a); Optional<String> emptyMap = emptyOptional.map(a -> "ageMap:" + age); Optional<String> nullMap = ageMap.map(a -> null); // 打印结果:Optional[ageMap:20] System.out.println(ageMap_); // 打印结果:Optional.empty System.out.println(emptyMap); // 打印结果:Optional.empty System.out.println(nullMap); ~~~ ### flatMap 如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper返回值必须是Optional。调用结束时,flatMap不会对结果用Optional封装。 ~~~ Optional<String> flat = Optional.of("hello flatMap"); Optional<String> flatMap = flat.flatMap(it -> Optional.of(it.toUpperCase())); // 打印结果:Optional[HELLO FLATMAP] System.out.println(flatMap); ~~~ ## 获取Optional的值 ### get get方法将获取Optional中value的值,如果存在值,则返回该值,否则抛出NoSuchElementException。 ~~~ Optional<String> getOptional = Optional.of("This is a Optional"); String valueOptional = getOptional.get(); // 打印结果:This is a Optional System.out.println(valueOptional); ~~~ ### orElse 如果Optional实例有值则将其返回,否则返回orElse方法传入的参数。 ~~~ //如果值不为null,orElse方法返回Optional实例的值。 //如果为null,返回传入的消息。 //输出:There is no value present! System.out.println(empty.orElse("There is no value present!")); //输出:Sanaulla System.out.println(name.orElse("There is some value!")); ~~~ ### orElseGet orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。 ~~~ //orElseGet与orElse方法类似,区别在于orElse传入的是默认值, //orElseGet可以接受一个lambda表达式生成默认值。 //输出:Default Value System.out.println(empty.orElseGet(() -> "Default Value")); //输出:Sanaulla System.out.println(name.orElseGet(() -> "Default Value")); orElseThrow ~~~ ### orElseThrow 在orElseGet方法中,我们传入一个Supplier接口。然而,在orElseThrow中我们可以传入一个lambda表达式或方法,如果值不存在来抛出异常。 ~~~ try { //orElseThrow与orElse方法类似。与返回默认值不同, //orElseThrow会抛出lambda表达式或方法生成的异常 empty.orElseThrow(ValueAbsentException::new); } catch (Throwable ex) { //输出: No value present in the Optional instance System.out.println(ex.getMessage()); } ~~~ # lambda和optional结合 比如以下代码 ~~~ if(authVo!=null){ String id=authVo.getId(); if(id==null) { id=""; } List<AuthVo> vos=authMapper.find(id); if(vos!=null){ for(AuthVo v : vos){ if(v!=null){ return v; } continue; } return new AuthVo(); } else { return new AuthVo(); } } else { return new AuthVo(); } ~~~ 通过java8的话,只需要这样写 ~~~ Optional.ofNullable(authVo).map(v -> { List<AuthVo> vos=authMapper.find(Optional.ofNullable(v.getId()).orElse("")); v=Optional.ofNullable(vos) .orElse(new ArrayList<AuthVo>()) .stream() .filter(vo -> vo!=null) .findFirst() .orElse(new AuthVo()); return v; }).orElse(new AuthVo()); ~~~