文档章节

java8 -函数式编程之Optional

细肉云吞
 细肉云吞
发布于 2018/12/24 11:37
字数 1404
阅读 898
收藏 8

前言

    在某些情况下,首先要判断某个参数或者某个方法的返回值是否为null,才能继续操作该参数。对于某些链式操作需要多次通过if语句判断是否为空,才能确保不抛出NullPointerException,这段非空判断的代码显得非常冗长和恶心。比如下面这段代码:

String isoCode = "default";
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            isocode = country.getIosCode();
            if (isocode != null) {
                isocode = isocode.toUpperCase();
            }
        }
    }
}

    在java 8里,JDK引入了一个Optional类,该类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。通过本文的学习,我们看下如何通过Optional类重写上面那段判空代码。

    接下来,我们一起学习Optional类的初始化和它里面的方法。lambda表达式和四个基本函数式接口是本文的基础,可以通过 java8 -函数式编程之Lambda表达式 和 java8 -函数式编程之四个基本接口 充分了解。

Optional初始化

    Optional类的构造方法是私有方法,所以只能通过它的静态工厂方法进行初始化。它的初始化方法有如下四种:

(1) <T> Optional<T> of (T value) :为非null的值创建一个Optional。如果传入参数为null,抛出NullPointerException。

//调用工厂方法创建Optional实例
Optional<String> name = Optional.of("hello");
//传入参数为null,抛出NullPointerException.
Optional<String> someNull = Optional.of(null);

(2)<T> Optional<T> ofNullable (T value) :为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional。它和 of 的区别是可以传null值。在它的实现代码中,如果传的值为null,会调用另一个静态工厂方法 empty 获取一个Optional对象

Optional empty = Optional.ofNullable(null);

(3)<T> Optional<T> empty () :ofNullable静态工厂方法,传null值时的实现,返回一个空的Optional。

Optional类的其它方法

(1)isPresent :如果值存在返回true,否则返回false。

// false
Optional<String> empty = Optional.ofNullable(null);
System.out.println(empty.isPresent());

// true
Optional<String> optionalS2 = Optional.of(s2);
System.out.println(optionalS2.isPresent());

(2)get:如果Optional有值则将其返回,否则抛出NoSuchElementException

//获取hello
Optional.of("hello").get();
//抛出NoSuchElementException
Optional.empty().get();

(3)void ifPresent (Consumer<? super T> consumer) :如果Optional实例有值则调用consumer,否则不做处理。

//调用ifPresent方法里面的consumer
Optional.of("hello")
        .ifPresent(System.out::println);

(4)orElse:如果有值则将其返回,否则返回指定的其它值


//输出:null
System.out.println(Optional.empty().orElse("null"));
//输出:hello
System.out.println(Optional.of("hello").orElse("null"));

(5)T orElseGet (Supplier<? extends T> other) :orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受 Supplier接口 的实现用来生成默认值。

//输出null
System.out.println(Optional.empty().orElseGet(() -> "null"));
//输出hello
System.out.println(Optional.of("hello").orElseGet(() -> "null"));

(6)<X extends Throwable> T orElseThrow (Supplier<? extends X> exceptionSupplier) throws X :如果有值则将其返回,否则抛出supplier接口创建的异常。


//抛出exception
try {
    Optional.empty().orElseThrow(()->new Exception("为空"));
} catch (Exception e) {
    e.printStackTrace();
}

(7)<U> Optional<U> map (Function<? super T, ? extends U> mapper) :如果参数 mapper 有值,则调用map方法执行mapper参数的Function方法得到返回值。如果mapper的返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。如果传入的mapper参数是null,抛出NullPointerException。

//输出 JACK
Optional<String> stringOptional = Optional.of("jack").map((value) -> value.toUpperCase());
System.out.println(stringOptional.orElse("default"));

//输出 default
Optional<String> stringOptional1 = Optional.of("jack").map((value) -> null);
System.out.println(stringOptional1.orElse("default"));

//输出 default,并且不会调用mapper
String s2 = null;
Optional<String> stringOptional2 = Optional.ofNullable(s2).map((value) -> value.toUpperCase());
System.out.println(stringOptional2.orElse("default"));

//如果参数mapper为null,抛NullPointerException异常
try {
    String s3 = null;
    Optional<String> stringOptional3 = Optional.ofNullable(s3).map(null);
    System.out.println(stringOptional3.orElse("default"));
} catch (Exception e) {
}

(8)<U> Optional<U> flatMap (Function<? super T, Optional<U>> mapper) :flatMap与map方法类似,区别在于flatMap中的mapper返回值必须是Optional。调用结束时,flatMap不会对结果用Optional封装。

//flatMap,输出 JACK
Optional<String> stringOptional4 = Optional.of("jack").flatMap((value) -> Optional.ofNullable(value.toUpperCase()));
System.out.println(stringOptional4.orElse("default"));

//flatMap,输出 default
Optional<String> stringOptional5 = Optional.of("jack").flatMap((value) -> Optional.ofNullable(null));
System.out.println(stringOptional5.orElse("default"));

//flatMap,输出 default,并且不会调用mapper
String s6 = null;
Optional<String> stringOptional6 = Optional.ofNullable(s6).flatMap((value) -> Optional.ofNullable(value.toUpperCase()));
System.out.println(stringOptional6.orElse("default"));

//flatMap 如果map的参数mapper为null,抛NullPointerException异常
try {
    String s7 = null;
    Optional<String> stringOptional7 = Optional.ofNullable(s7).flatMap(null);
    System.out.println(stringOptional7.orElse("default"));
} catch (Exception e) {
    System.out.println("出错了");
}

(9)Optional<T> filter (Predicate<? super T> predicate) :如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。


//输出default
String filterString = Optional.of("hugo")
        .filter(s -> "jack".equals(s))
        .orElse("default");
System.out.println(filterString);
//输出hugo
String filterString2 = Optional.of("hugo")
        .filter(s -> "hugo".equals(s))
        .orElse("default");
System.out.println(filterString2);
//输出default,断言接口里面的语句不会执行
String nullableString = null;
String filterString3 = Optional.ofNullable(nullableString)
        .filter(s -> {
            System.out.println("测试是否调用");
            return "jack".equals(s);
        })
        .orElse("default");
System.out.println(filterString3);

 

解决问题

经过上面学习Optional的相关API,已经对它有了一定的了解。下面,我们运用上面的知识解决在前言中遗留的问题。

ioscode = Optional.ofNullable(user)
        .map(u -> u.getAddress())
        .map(addr -> addr.getCountry())
        .map(country -> country.getIosCode())
        .map(String::toUpperCase)
        .orElse("default");

从上面的学习可以知道,只有Optional是empty的,map方法不会被调用。

相关资料

Java 8 函数式编程系列

    java8 -函数式编程之Lambda表达式

    java8 -函数式编程之四个基本接口

    java8 -函数式编程之Optional

    java8 -函数式编程之Stream

© 著作权归作者所有

细肉云吞

细肉云吞

粉丝 122
博文 296
码字总数 203317
作品 1
其它
高级程序员
私信 提问
加载中

评论(1)

黑夜中的城的微风
学习了
Java函数式开发——优雅的Optional空指针处理

那些年困扰着我们的null 在Java江湖流传着这样一个传说:直到真正了解了空指针异常,才能算一名合格的Java开发人员。在我们逼格闪闪的java码字符生涯中,每天都会遇到各种null的处理,像下面...

随风溜达的向日葵
2016/08/28
1W
24
Java Optional空指针处理

那些年困扰着我们的null 在Java江湖流传着这样一个传说:直到真正了解了空指针异常,才能算一名合格的Java开发人员。在我们逼格闪闪的java码字符生涯中,每天都会遇到各种null的处理,像下面...

溜达向日葵
2018/08/13
0
0
java8 -函数式编程之四个基本接口

不管lambda表达式还是Stream流式编程,Function、Consumer、Supplier、Predicate 四个接口是一切函数式编程的基础。下面我们详细学习这四个巨头, interface Supplier<T> 该接口的中文直译是...

细肉云吞
2018/12/24
673
0
java8 -函数式编程之Stream

在 java8 -函数式编程之Lambda表达式、 java8 -函数式编程之四个基本接口 、java8 -函数式编程之Optional 三篇文章中,我们已经对函数式编程有了充分的了解,接下来,我们将会运用之前学到的...

细肉云吞
2018/12/24
976
1
java8中Collection新增方法详解

文章目录 Java8中Stream的使用 Collection新增方法: removeIf stream parallelStream spliterator list中 replaceAll sort removeIf 作用是删除容器中所有满足filter指定条件的元素 比如: ...

兴国First
2019/09/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

如何让图卷积网络变深?腾讯AI Lab联合清华提出DropEdge

  机器之心发布   机器之心编辑部      近年来,图神经网络的研究异常火爆,被各大顶会录取的文章数量爆炸式增长。然而,目前大部分图卷积网络,尤其是面向节点分类的网络,都是浅层...

osc_v1ao43h5
2分钟前
6
0
疫情夹缝中的顶会ECCV:程序主席一度失联,投稿热情不减

  机器之心报道   参与:蛋酱、张倩      程序主席都病了,今年的 ECCV 要怎么办?   据外媒报道,英国首相鲍里斯·约翰逊因新冠病情恶化转入 ICU,成为受新冠严重影响的另一位政要...

osc_hzf6peqc
3分钟前
0
0
李飞飞团队最新研究 :「四步」AI方案助老人抵抗新冠肺炎

      自2018年回归学术界后,李飞飞教授便很少对外露面,近日在一次斯坦福的线上会议,让我们有机会了解她与团队的最新研究——《AI-ASSISTED IN-HOME ELDERLY CARE AMID COVID-19 PAND...

osc_cyo5y1ey
5分钟前
5
0
人脸识别再曝安全漏洞:清华创业团队推出全球首个AI模型杀毒软件

  机器之心报道   参与:泽南   瑞莱智慧刚刚发布的首个 AI 安全平台,发现了迄今为止最为「重大」的人脸识别安全漏洞。   4 月 7 日,来自清华的 RealAI(瑞莱智慧)发布了 RealSa...

osc_2uc536xl
6分钟前
6
0
BigDecimal除法后保留两位小数

BigDecimal cnt;BigDecimal totalCnt = new BigDecimal(total); cnt = new BigDecimal(po.getId() * 100);Double d = cnt.divide(totalCnt, 2, BigDecimal.ROUND_HALF_UP).doubleValue()......

zxx901221
6分钟前
17
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部