文档章节

java8 -函数式编程之Optional

细肉云吞
 细肉云吞
发布于 2018/12/24 11:37
字数 1404
阅读 894
收藏 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
672
0
java8 -函数式编程之Stream

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

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

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

兴国First
2019/09/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

RabbitMQ消息中间件技术精讲笔记

[TOC] RabbitMQ消息中间件技术精讲笔记 错别字有点多, 改了一部分. 剩下的不影响阅读,实在没精力改了... 业界主流消息中间件介绍 MQ衡量指标 服务性能 数据存储 集群架构 主流MQ介绍 Active...

我爱吃炒鸡
昨天
17
0
从"曼巴精神"中学到的做事方式

致敬曼巴 最近一直想写一篇关于曼巴精神的文章,作为科比球迷,今年发生的事情的确让我们难过,不过生活还要继续,虽然科比已经离开了我们,但曼巴精神永存,下面从几点来讲述曼巴精神在我们...

科比可比克
昨天
31
0
使用JavaScript在文本框中的Enter键上触发按钮单击

问题: I have one text input and one button (see below). 我有一个文本输入和一个按钮(见下文)。 How can I use JavaScript to trigger the button's click event when the Enter key ......

技术盛宴
昨天
27
0
展示如何在checkout里使用quote,quote item, address, shopping cart

展示如何更改并且在定制化的时候高效应用这些模块。 以下实体继承 \Magento\Framework\Model\AbstractExtensibleModel ,所以你可以使用第4章中讨论的可扩展属性。 Quote Quotes 是客户购物车...

忙碌的小蜜蜂
昨天
28
0
面向对象思想设计原则及常见设计模式

1、面向对象思想设计原则 在实际的开发中,我们要想更深入的了解面向对象思想,就必须熟悉前人总结过的面向对象的思想的设计原则 1.1、单一职责原则 高内聚,低耦合 每个类应该只有一个职责,...

庭前云落
昨天
31
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部