优雅解决空指针问题——Optional类的使用

前言

空指针是java程序员在工作中遇到的最多的异常之一,对于对象中的某个属性,有时候我们为了避免程序报空指针错误,而不得不使用较多的ifelse来进行逻辑判断,但这样的话代码可能就会比较冗余或者说不够优雅。在JDK1.8中,提供了Optional类为我们解决空指针问题提供了一种方式,有需要的同学可以参考一下本篇文章。

先讲一个小例子

假如我们想获取Student类中省份信息,我们需要执行的代码如下:

链式的get方法获取对象的属性值

这种方法存在空指针的隐患,当出现Address为空甚至是Student对象为空的情况,此时我们就不得不通过条件判断语句来避免空指针的产生;
多个if、else语句造成代码的冗余

而使用Optonal后解决方式如下:

public class OptionalTest {

    public static void main(String[] args) {
        Student student = new Student("小明",16,null);
        String result = new OptionalTest().OptGetProvince(null);
        System.out.println(result);
    }
    public String OptGetProvince(Student student){
        return Optional.ofNullable(student)
                .map(s -> s.getAddress())
                .map(a -> a.getProvince())
                .orElse("none");
    }
}

可以看到,通过Optional的使用,使得整体的判断变得十分的清爽简洁。
讲讲我对Optional类的理解:我们可以把该类看成是一个容器,我们将对象存储到容器中后,通过调用内置的api,可以较为安全地过滤掉可能存在的空指针问题,避免繁琐的if、else操作。让我们的代码尽可能的简洁

Optional的常见API

(一)构造函数: empty,of,ofNullable
1. empty返回一个空的Optional对象
Optional.empty();
2. of根据传入的值生成Optional对象
// 方式2 将非空对象作为属性传入Optional类中
Student s = new Student("小明",16);
 Optional.of(s.getAddress());
3. ofNullable 和of方法一样,根据传入的值生成optional对象
// 方式3 将非空对象作为属性传入Optional类中
 Student s = new Student("小明",16);
 Optional.ofNullable(s.getAddress());

我们可以发现,ofofNullable的作用很相近,实际上,进入Optional类的源代码看的话,可以发现对于ofNullable方法的话是有进行判空的。也就是说,如果使用of方法传入的参数是null,同样会报空指针!!!

image.png

(二)值选择方法:orElseorElseGetorElseThrow

上述的三个方法相当于是SQL中的NVL函数,若Optional中值为null,则给定一个默认值。

1、orElse
Student s = new Student("小明",16,new Address());
String result = Optional.ofNullable(s.getAddress().getProvince()).orElse("北京");
2、orElseGet
 Student s = new Student("小明",16,new Address());
String result = Optional.ofNullable(s.getAddress().getProvince()).orElseGet(()->"北京");
3、orElseThrow
Student s = new Student("小明",16,new Address());
String s3 = Optional.ofNullable(s.getAddress().getProvince()).orElseThrow(() -> new IllegalArgumentException("缺少参数"));

我们可以发现,对于orElseThroworElseGet两个方法,是采用函数式接口的方式来作为参数的。
同时,对于orElseorElseGet两个方法,作用相近,具体有哪些不同呢?
答案是若Optional对象中的值不为空,则orElseGet不会创建参数中的对象,而orElse无论什么情况都会创建参数对象。

Optional.ofNullable(new Student("小明",16)).orElseGet(()->new Student("小红",17));
上面这条式子,会创建两个student对象
(三)值转换函数:map和flagMap

值转换的意思是对Optional对象中的value值进行转换,对值应用(调用)作为参数的函数,然后将返回的值包装在 Optional

1、map
Student student = new Student("小明",16,new Address());
String s1 = Optional.ofNullable(student).map(s -> s.getName()).get();
2、flagMap
Student student = new Student("小明",16,new Address());
String s1 = Optional.ofNullable(student).flatMap(s -> s.getName()).get();

两个函数都可以实现值的转换,那么两者的区别在哪呢?答案是二者的入参不同

map和flatMap的源码对比

以上面的flagMap的示例代码为例,我们需要在Student类中重写一下getName方法,使其返回Optional对象

public class Student  {
  private String name;
   public Optional<String> getName() {
        return Optional.ofNullable(this.name);
    }
}
(四)判空函数:isPresent和ifPresent

两个函数的用法类似,都可以用作判空,区别在于当不为空时,ifPresent会执行对应的函数。

1. isPresent
Student student = new Student("小明",16,new Address());
boolean b1 = Optional.ofNullable(student.getAddress()).isPresent();
System.out.println(b1);  // true
2. ifPresent
Student student = new Student("小明",16,new Address());
Optional.ofNullable(student.getAddress()).ifPresent(address -> System.out.println(address));
(五)过滤(筛选)函数:filter

该函数的作用是,判断Optional中的值是否满足指定条件,若满足则返回,否则返回一个EMPTY对象。

Student student = new Student("小明",16,new Address());
Student result = Optional.ofNullable(student).filter(s -> s.getName().equals("小红")).orElseGet(() ->new Student("小蓝",10));
System.out.println(result); // Student{address=null, name='小蓝', age=10}

这里会筛选出满足姓名为小红的Student对象,若不满足则新建一个姓名为小蓝的Student对象。

到这里,关于Optional类的常用api已经介绍完毕,相信大家通过这篇文章可以了解该类的作用和使用,要想熟练地进行应用,还需要大家在日常开发中的使用。
下面再总结一些常见的优化场景
优化前

    public String originTest(Student student){
        if(null != student){
            Address address = student.getAddress();
            if(null != address){
                String province = address.getProvince();
                if(null != province){
                    return province;
                }
            }
        }
        return null;
    }

优化后

    public String optimizeTest(Student student) {
        return  Optional.ofNullable(student)
                .map(s -> s.getAddress())
                .map(a -> a.getProvince())
                .orElse("none");
    }

优化前

    public void originTest(Student student){
        if(null != student){
            // dosomething
        }
    }

优化后

Optional.ofNullable(student)
         .ifPresent(s -> doSomeThing);

写在最后

OptionalJava8推出的一个小特性,在一些get语句嵌套比较多的场景,比较适合运用,学习成本也不算高(其源码比较简单),但也需要注意,使用Optonal在简洁化代码的同时,相对来说会损失一定的代码可读性,具体的使用也要开发人员在实际场景中加以权衡后使用。
个人建议的话,哪怕是自己不使用也要尽量掌握,避免出现阅读源码的时候出现障碍。

参考文章:
1、Java中Optional类的使用 https://blog.csdn.net/wwe4023/article/details/80760416
2、JAVA8之妙用Optional解决判断Null为空的问题 http://www.ibloger.net/article/3209.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容