Java8新特性之五:Optional_weixin_34342905的博客-程序员秘密

技术标签: java  数据库  

  NullPointerException相信每个JAVA程序员都不陌生,是JAVA应用程序中最常见的异常。之前,Google Guava项目曾提出用Optional类来包装对象从而解决NullPointerException。受此影响,JDK8的类中也引入了Optional类,在新版的SpringData Jpa和Spring Redis Data中都已实现了对该方法的支持。

1、Optional类

 1 /**
 2  * A container object which may or may not contain a non-null value.
 3  * If a value is present, {
     @code isPresent()} will return {
     @code true} and
 4  * {
     @code get()} will return the value.
 5  *
 6  * @since 1.8
 7  */
 8 public final class Optional<T> {
 9     /**
10      * Common instance for {
     @code empty()}.
11      */
12     private static final Optional<?> EMPTY = new Optional<>();
13 
14     /**
15      * If non-null, the value; if null, indicates no value is present
16      */
17     private final T value;
18 
19    // 其他省略
20 }

  该方法的注释大致意思是:Optional是一个容器对象,它可能包含空值,也可能包含非空值。当属性value被设置时,isPesent()方法将返回true,并且get()方法将返回这个值。

  该类支持泛型,即其属性value可以是任何对象的实例。

2、Optional类的方法

    序号    

方法

方法说明
1
private Optional()
 无参构造,构造一个空Optional
2
private Optional(T value)
 根据传入的非空value构建Optional
3
public static<T> Optional<T> empty()
返回一个空的Optional,该实例的value为空
4  
public static <T> Optional<T> of(T value)
根据传入的非空value构建Optional,与Optional(T value)方法作用相同
5  
public static <T> Optional<T> ofNullable(T value)

 与of(T value)方法不同的是,ofNullable(T value)允许你传入一个空的value,

当传入的是空值时其创建一个空Optional,当传入的value非空时,与of()作用相同

6  
public T get()
 返回Optional的值,如果容器为空,则抛出NoSuchElementException异常
7  
public boolean isPresent()
 判断当家Optional是否已设置了值
8  
public void ifPresent(Consumer<? super T> consumer)
 判断当家Optional是否已设置了值,如果有值,则调用Consumer函数式接口进行处理
9  
public Optional<T> filter(Predicate<? super T> predicate)
 如果设置了值,且满足Predicate的判断条件,则返回该Optional,否则返回一个空的Optional
10  
public<U> Optional<U> map(Function<? super T, ? extends U> mapper)

 如果Optional设置了value,则调用Function对值进行处理,并返回包含处理后值的Optional,否则返回空Optional

11  
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
 与map()方法类型,不同的是它的mapper结果已经是一个Optional,不需要再对结果进行包装
12  
public T orElse(T other)
 如果Optional值不为空,则返回该值,否则返回other 
13
public T orElseGet(Supplier<? extends T> other)
如果Optional值不为空,则返回该值,否则根据other另外生成一个
14
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)
throws X
如果Optional值不为空,则返回该值,否则通过supplier抛出一个异常

3、Optional类的方法举例

  《Java 8 Features Tutorial – The ULTIMATE Guide》中给出了两个简单的例子,我们从这两个例子入手来简单了解一下Optional容器的使用。

  示例一:

1 public static void main(String[] args) {
2   Optional< String > fullName = Optional.ofNullable( null );
3   System.out.println( "Full Name is set? " + fullName.isPresent() );
4   System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) );
5   System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
6 }

  运行结果:

Full Name is set? false
Full Name: [none]
Hey Stranger!  

  说明:

  ifPresent()方法当Optional实例的值非空时返回true,否则返回false; 

  orElseGet()方法当Optional包含非空值时返回该值,否则通过接收的function生成一个默认的;

  map()方法转换当前Optional的值,并返回一个新的Optional实例;

  orElse()方法与orElseGet方法相似,不同的是orElse()直接返回传入的默认值。

 

  示例二:修改示例一,使其生成一个非空值的Optional实例

1 Optional< String > firstName = Optional.of( "Tom" );
2 System.out.println( "First Name is set? " + firstName.isPresent() );
3 System.out.println( "First Name: " + firstName.orElseGet( () -> "[none]" ) );
4 System.out.println( firstName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );

  输出结果:

First Name is set? true
First Name: Tom
Hey Tom!

  可以清晰地看出与示例一的区别。这不但简洁了我们的代码,而且使我们的代码更便于阅读。

  下面看一下例子中使用到的几个方法的源码:

  1)、of

1 public static <T> Optional<T> of(T value) {
2   return new Optional<>(value);
3}

  2)、isPresent

1 public boolean isPresent() {
2    return value != null;
3 }

  3)、orElseGet

1 public T orElseGet(Supplier<? extends T> other) {
2     return value != null ? value : other.get();
3 }

  4)、orElse

1 public T orElse(T other) {
2     return value != null ? value : other;
3 }

  其他方法源码,读者可以去Optional源码中查看。

4、使用Optional避免空指针

  在我们日常开发过程中不可避免地会遇到空指针问题,在以前,出现空指针问题,我们通常需要进行调试等方式才能最终定位到具体位置,尤其是在分布式系统服务之间的调用,问题更难定位。在使用Optional后,我们可以将接受到的参数对象进行包装,比如,订单服务要调用商品服务的一个接口,并将商品信息通过参数传入,这时候,传入的商品参数可能直接传入的就是null,这时,商品方法可以使用Optional.of(T)对传入的对象进行包装,如果T为空,则会直接抛出空指针异常,我们看到异常信息就能立即知道发生空指针的原因是参数T为空;或者,当传入的参数为空时,我们可以使用Optional.orElse()或Optional.orElseGet()方法生成一个默认的实例,再进行后续的操作。

  下面再看个具体例子:在User类中有个Address类,在Address类中有个Street类,Street类中有streetName属性,现在的需求是:根据传入的User实例,获取对应的streetName,如果User为null或Address为null或Street为null,返回“nothing found”,否则返回对应的streetName。

  实现一:

1 @Data
2 public class User {
3     private String name;
4     private Integer age;
5     private Address address;
6 }
1 @Data
2 public class Address {
3     private Street street;
4 }
1 @Data
2 public class Street {
3     private String streetName;
4     private Integer streetNo;
5 }
 1 public String getUserSteetName(User user) {
 2 
 3     if(null != user) {
 4 
 5         Address address = user.getAddress();
 6 
 7         if(null != address) {
 8 
 9             Street street = address.getStreet();
10 
11             if(null != street) {
12                 return street.getStreetName();
13             }
14         }
15     }
16 
17     return "nothing found";
18 }

  实现二,使用Optional:

   在实现一中明显的问题是if判断层级太深,下面复用Optional改写:

1 @Data
2 public class User {
3     private String name;
4     private Integer age;
5     private Optional<Address> address = Optional.empty();
6 }
1 @Data
2 public class Address {
3     private Optional<Street> street = Optional.empty();
4 }
1 @Data
2 public class Street {
3     private String streetName;
4     private Integer streetNo;
5 }
1 public String getUserSteetName(User user) {
2 
3     Optional<User> userOptional = Optional.ofNullable(user);
4     final String streetName = userOptional.orElse(new User()).getAddress().orElse(new Address()).getStreet().orElse(new Street()).getStreetName();
5     return StringUtils.isEmpty(streetName) ? "nothing found" : streetName;
6 }

  利用orElse()方法给定默认值的方式确保不会报空指针问题问题,同时也能实现需求。

转载于:https://www.cnblogs.com/wuhenzhidu/p/10765655.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_34342905/article/details/93334235

智能推荐

acm数论之欧几里得gcd_weixin_33859665的博客-程序员秘密

1.欧几里得定理同余定理的公式:(a+b)%mod=(a%mod+b%mod)%mod (a*b)%mod=(a%mod*b%mod)%mod 扩展欧几里得也有自己的一个公式:a*x+b*y=gcd(a,b)1.1定义:gcd(a,b)=gcd(b,a%b)1.2用法:获得最大公约数与最小公倍数----...

cadence16.6 如何对齐元件_weixin_33979203的博客-程序员秘密

1.选中Setup——&gt;Application Mode——&gt;Placement Edit mode2.按“CTRL”键,选中需要对齐的所有对象。3.点击右键右,或者在空白处按住Shift右键单击,选择Align component. 注意,如果元件散落成X,Y方向都有可能对齐的样式,软件会选择其中不会造成Align后元件重叠的那种方向进行对齐。(对齐的方向好像不能设置...

JavaScript jsonp解决跨域问题_cjn.的博客-程序员秘密

产生跨域原因[浏览器同源策略]:协议不同(http/https)、域名不同、端口不同演示下出现跨域的情况,请求豆瓣api:http://api.douban.com/v2/movie/top250jquery-ajax请求function req_test () { var url = &quot;http://api.douban.com/v2/movie/top250&quot; $.ajax...

java实现系列化的jdk_JAVA序列化和反序列化的底层实现原理解析_冬瓜哥已被Jin言的博客-程序员秘密

一、基本概念1、什么是序列化和反序列化(1)java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程;(2)**序列化:**对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。序列化后的字节流保存了Java对象的状态以及相关的描述信息。序列化机制的...

在线Word转PDF的妙招,快来收藏!_chongdao6640的博客-程序员秘密

不论是学生党还是办公党,Microsoft office套件都是大伙儿装机必备的工具。通过微软几次升级,现在市面上存在多种版本的Microsoft office套件,常见的有2003版、2007版、2010版等,不少小伙伴习惯了其中的一个版本之后,就懒得再去更新。这就导致了一种版本的offic...

.net core 3.1 swagger文档_chafferer_的博客-程序员秘密

.net core 3.1 swagger文档1.安装包Swashbuckle.AspNetCore2.在Startup.cs 配置swagger 在ConfigureServices中添加代码services.AddSwaggerGen(c =&gt; { c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" }); ...

随便推点

在美国打高尔夫的规矩_cishan3804的博客-程序员秘密

北京的Steve Qiao认为高尔夫像麻将,是可以打出感情,打出品性的,是很好的商务工具。天气好的时候他一周要跟客户打五、六场球。身为科技公司中国计费网创始人的Steve在美国呆过16年,两头都算球迷。他在国内打球的最大感受是,...

更改Tomcat日志目录_程裕强的博客-程序员秘密

1、修改conf/logging.properties[[email protected] apache-tomcat-8.5.35]# vi conf/logging.properties############################################################# Handler specific properties.# Describes sp...

在虚拟机或Docker中搭建大数据伪分布式集群(四):添加 Spark_一叶知秋叶若秋的博客-程序员秘密

在虚拟机或Docker中搭建大数据伪分布式集群(四):添加 Spark系列文章:在虚拟机或Docker中搭建大数据伪分布式集群系列(一):hadoop基础功能——hdfs 与 yarn在虚拟机或Docker中搭建大数据伪分布式集群(二):集群添加zookeeper与HBase在虚拟机或Docker中搭建大数据伪分布式集群(三):添加Hive接下来搭建Spark...

css3之呼吸灯效果_weixin_33861800的博客-程序员秘密

为什么80%的码农都做不了架构师?&gt;&gt;&gt; ...

刘汝佳 开灯问题(C++版)_c++实现算法动画开灯问题_cscp1的博客-程序员秘密

#include#includeusing namespace std;int main(){    int n,k;    while(cin>>n>>k)    {        bool first=true;        int a[1010];        memset(a,1,sizeof(a));        for(int i=2;

java inputreader_Java 之 InputStreamReader 类_Yaooo5的博客-程序员秘密

InputStream 类1、概述转换流 java.io.InputStreamReader ,是Reader的子类,是从字节流到字符流的桥梁。该类读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。2、继承自父类的共性成员方法该类继承于 Reader 类,继承了父类的共性成员方法:int read() 读取单个字符并返回。int read(char[...

推荐文章

热门文章

相关标签