您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
Optional源码解析与实践
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
Optional源码解析与实践
自猿其说Tech
2022-08-30
IP归属:未知
38280浏览
计算机编程
### 1 导读 NullPointerException在开发过程中经常遇到,稍有不慎小BUG就出现了,如果避免这个问题呢,Optional就是专门解决这个问题的类,那么Optional如何使用呢?让我们一起探索一下吧! ### 2 源码解析 #### 2.1 Optional定义 Optional类是Java8为了解决null值判断问题而创建的容器类,在java.util 下,使用Optional类可以避免显式的null值判断,避免null导致的NullPointerException。首先,Optional是一个容器,它可以保存类型T的值,也可以为null的容器对象。Optional容器只能存一个值。 #### 2.2 Optional的属性 ###### 1)源码: ```java /** * Common instance for {@code empty()}. */ private static final Optional<?> EMPTY = new Optional<>(); /** * If non-null, the value; if null, indicates no value is present */ private final T value; ``` 根据源码可以看到Optional有两个属性,一个是为空值准备的EMPTY和泛型值value; #### 2.3 Optional的方法 Optional除toString()、hashCode() 、equals()等Object的方法外,还包含以下方法。 ##### 2.3.1 私有构造方法 ```java /** * Constructs an empty instance. * * @implNote Generally only one empty instance, {@link Optional#EMPTY}, * should exist per VM. */ private Optional() { this.value = null; } /** * Constructs an instance with the value present. * * @param value the non-null value to be present * @throws NullPointerException if value is null */ private Optional(T value) { this.value = Objects.requireNonNull(value); } ``` 分别是创建一个空实例和构造一个具有当前值的实例。 ##### 2.3.2 创建方法 ###### 1)源码 ```java public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") 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); } ``` ###### 2)方法说明 - empty(): 创建一个空的 Optional 实例 - of(T t) : 创建一个 Optional 实例,当 t为null时抛出异常 - ofNullable(T t): 创建一个 Optional 实例,但当 t为null时不会抛出异常,而是返回一个空的实例 3)测试代码 ```java public static void main(String[] args) { Integer value1 = null; Integer value2 = 1; try { Optional<Integer> optional1 = Optional.empty(); System.out.println("optional1创建了"); }catch (Exception e){ System.out.println("optional1失败了"); } try { Optional<Integer> optional2 = Optional.of(value1); System.out.println("optional2创建了"); }catch (Exception e){ System.out.println("optional2失败了"); } try { Optional<Integer> optional3 = Optional.ofNullable(value1); System.out.println("optional3创建了"); }catch (Exception e){ System.out.println("optional3失败了"); } try { Optional<Integer> optional4 = Optional.of(value2); System.out.println("optional4创建了"); }catch (Exception e){ System.out.println("optional4失败了"); } try { Optional<Integer> optional5 = Optional.ofNullable(value2); System.out.println("optional5创建了"); }catch (Exception e){ System.out.println("optional5失败了"); } } ``` 4)运行结果 ![](//img1.jcloudcs.com/developer.jdcloud.com/f3c6a753-1458-4f62-9e44-6b9fd5dd50dc20220830115631.png) ##### 2.3.3 值获取方法 ###### 1)源码 ```java public T get() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; } ``` ###### 2)方法说明 get(): 如果Optional不为空,则返回该Optional容器中的值,否则抛出NoSuchElementExceptio 。 ###### 3)测试代码 ```java public static void main(String[] args) { Integer value1 = null; Integer value2 = 1; Optional<Integer> optional1 = Optional.ofNullable(value1); Optional<Integer> optional2 = Optional.of(value2); try { Integer result=optional1.get(); System.out.println("optional1的值是:"+result); }catch (Exception e){ System.out.println("optional1的值获取失败,原因:"+e.getMessage()); } try { Integer result=optional2.get(); System.out.println("optional2的值是:"+result); }catch (Exception e){ System.out.println("optional2的值获取失败,原因:"+e.getMessage()); } } ``` ###### 4)运行结果 ![](//img1.jcloudcs.com/developer.jdcloud.com/8b2c7b3a-1d98-4aec-b2ac-8e0648dd34fe20220830115736.png) ##### 2.3.4 判断方法 ###### 1)源码 ```java public boolean isPresent() { return value != null; } public void ifPresent(Consumer<? super T> consumer) { if (value != null) consumer.accept(value); } public T orElse(T other) { return value != null ? value : other; } public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); } public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); } } ``` ###### 2)方法说明 - isPresent(): 判断optional是否为空,如果空则返回false,否则返回true - ifPresent(Consumer c): 如果optional不为空,则将optional中的对象传给Comsumer函数 - orElse(T other): 如果optional不为空,则返回optional中的对象;如果为null,则返回 other 这个对象。 - orElseGet(Supplier<T> other): 如果optional不为空,则返回optional中的对象;如果为null,否则调用其他函数并返回调用的结果 - orElseThrow(Supplier<X> exception): 如果optional不为空,则返回optional中的对象;如果为null,则抛出Supplier函数生成的异常 ###### 3)测试代码 ```java public static void main(String[] args) { Integer value1 = null; Integer value2 = 1; Optional<Integer> optional1 = Optional.ofNullable(value1); Optional<Integer> optional2 = Optional.of(value2); try { if(optional1.isPresent()){ System.out.println("optional1的isPresent结果不为空"); }else{ System.out.println("optional1的isPresent结果为空"); } }catch (Exception e){ System.out.println("optional1的isPresent判空失败,原因:"+e.getMessage()); } try { if(optional2.isPresent()){ System.out.println("optional2的isPresent结果不为空"); }else{ System.out.println("optional2的isPresent结果为空"); } }catch (Exception e){ System.out.println("optional2的isPresent判空失败,原因:"+e.getMessage()); } optional1.ifPresent(t->{ int i =t+1; System.out.println("optional1处理后的值是"+i); }); optional2.ifPresent(t->{ int i =t+1; System.out.println("optional2处理后的值是"+i);}); Integer value3 = 2; Integer result = optional1.orElse(value3); System.out.println("optional1执行orElse处理后的值是"+result); result = optional2.orElse(value3); System.out.println("optional2执行orElse处理后的值是"+result); result = optional1.orElseGet(()-> new Integer(-1)); System.out.println("optional1执行orElseGet处理后的值是"+result); result = optional2.orElseGet(()-> new Integer(-1)); System.out.println("optional2执行orElseGet处理后的值是"+result); try { result = optional1.orElseThrow (()-> new RuntimeException("值是空的")); System.out.println("optional1执行orElseThrow处理后的值是"+result); }catch (Exception e){ System.out.println("optional1的orElseThrow抛出异常:"+e.getMessage()); } try { result = optional2.orElseThrow (()-> new RuntimeException("值是空的")); System.out.println("optional2执行orElseThrow处理后的值是"+result); }catch (Exception e){ System.out.println("optional2的orElseThrow抛出异常:"+e.getMessage()); ``` ###### 4)运行结果 ![](//img1.jcloudcs.com/developer.jdcloud.com/fcfce01d-35a6-49a1-b27a-5324a88b6be620220830115849.png) ##### 2.3.5 过滤方法 ###### 1)源码 ```java public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); } ``` ###### 2)方法说明 filter(Predicate<T> p): 如果optional不为空,则执行Predicate p,如果p的结果为true,则返回原本的optional,否则返回空的optional ###### 3)测试代码 ```java public static void main(String[] args) { Integer value1 = 5; Integer value2 = 6; Optional<Integer> optional1 = Optional.ofNullable(value1); Optional<Integer> optional2 = Optional.of(value2); Optional<Integer> result =optional1.filter(t->t > 5); System.out.println("optional1的filter后的值:"+result); result =optional2.filter(t->t > 5); System.out.println("optional2的filter后的值:"+result); ``` ###### 4)运行结果 ![](//img1.jcloudcs.com/developer.jdcloud.com/20106d82-071c-4e9e-afc4-fc0a3b69296b20220830120151.png) ##### 2.3.6 映射方法 ###### 1)源码 ```java 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)); } } 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)); } } ``` ###### 2)方法说明 - map(Function<T, U> mapper): 如果存在一个值,则对其应用提供的映射函数,如果结果非空,则返回描述结果的Optional。 否则返回一个空的Optional。 - flatMap(Function< T,Optional<U>> mapper): 如果有值,则对其应用提供的可选映射函数,返回结果,否则返回空的可选函数。 这个方法类似于map(Function),但是提供的映射器的结果已经是一个可选的,如果调用,flatMap不会用额外的可选的包装它。 - 区别:map会自动将u放到optional中,而flatMap则需要手动给u创建一个optional ###### 3)测试代码 ```java public static void main(String[] args) { User user1 = null; User user2 = new User("user2名字",19); Optional<User> optional1 = Optional.ofNullable(user1); Optional<User> optional2 = Optional.of(user2); System.out.println("=========map=========="); System.out.println("optional1的map前的值:"+optional1); Optional<String> result =optional1.map(t->t.getName()); System.out.println("optional1的map后的值:"+result); System.out.println("optional2的map前的值:"+optional2); result =optional2.map(t->t.getName()); System.out.println("optional2的map后的值:"+result); System.out.println("===========flatMap========"); System.out.println("optional1的flatMap前的值:"+optional1); Optional<Integer> result2 =optional1.flatMap(t->Optional.ofNullable(t.getAge())); System.out.println("optional1的flatMap后的值:"+result2); System.out.println("optional2的flatMap前的值:"+optional2); result2 =optional2.flatMap(t->Optional.ofNullable(t.getAge())); System.out.println("optional2的flatMap后的值:"+result2); } public class User { String name; Integer age; public User(String name,Integer age){ this.name = name; this.age=age; } public String getName() { return name; } public Integer getAge() { return age; ``` ###### 4)运行结果 ![](//img1.jcloudcs.com/developer.jdcloud.com/3118dd1f-a96b-4bc8-8263-f611461a8a2a20220830120117.png) ### 3 应用实例 #### 3.1 错误用法 - 由于Optional并没有实现Serializable接口,所以不能作为类的属性。 - 不要把Optional作为方法的参数。 - 把if(x!=null)直接换成Optional.ofNullable(x).isPresent(),这样有过度编码的嫌疑。 - 直接使用Optional.get()的返回值进行操作,String result =Optional.ofNullable(null).get().toString();这样还是会抛出异常的。 #### 3.2 建议用法 A类有属性B类,B类有属性C类,C类有name这个字段。 使用Optional之前: ```java if(atest!=null){ Btest btest =atest.getBtest(); if(btest!=null){ Ctest ctest = btest.getCtest(); if (ctest != null) { name =ctest.getName(); } } } ``` 使用Optional之后: ```java name = Optional.ofNullable(atest).map(t->t.getBtest()).map(t->t.getCtest()).map(t->t.getName()).orElse("默认值"); ``` 代码是不是看上去更整洁了呢? ### 4 总结 通过对Optional源码解析和用例测试代码的运行结果,可以看出使用Optional可以优化null值判断代码,让代码变得更加优雅和整洁。 ------------ ###### 自猿其说Tech-JDL京东物流技术与数据智能部 ###### 作者:陈昌浩
原创文章,需联系作者,授权转载
上一篇:高并发下丢失更新的解决方案
下一篇:电商通用型商品中心设计
相关文章
Taro小程序跨端开发入门实战
Flutter For Web实践
配运基础数据缓存瘦身实践
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。
01
Taro小程序跨端开发入门实战
为了让小程序开发更简单,更高效,我们采用 Taro 作为首选框架,我们将使用 Taro 的实践经验整理了出来,主要内容围绕着什么是 Taro,为什么用 Taro,以及 Taro 如何使用(正确使用的姿势),还有 Taro 背后的一些设计思想来进行展开,让大家能够对 Taro 有个完整的认识。
01
Flutter For Web实践
Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践
01
配运基础数据缓存瘦身实践
在基础数据的常规能力当中,数据的存取是最基础也是最重要的能力,为了整体提高数据的读取能力,缓存技术在基础数据的场景中得到了广泛的使用,下面会重点展示一下配运组近期针对数据缓存做的瘦身实践。
自猿其说Tech
文章数
426
阅读量
2149964
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号