学习Java8中Optional

简介: Optional 类主要是为了解决(NullPointerException)空指针异常 。本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。Optional 是 Java 实现函数式编程的强劲一步,并且帮助在范式中实现。但是 Optional 的意义显然不止于此。

一、Java8之前访问对象的属性或方法

Java8之前访问对象的属性或方法,会使用到以下方式,以下方式可能会造成空指针异常

Stringcode=user.getAddress().getCountry().getCode().toUpperCase();

在上面的代码中,如果要确保不发生空指针异常必须使用非空判断,如下所示

if (null!=user) {
Addressaddress=user.getAddress();
if (null!=address ) {
Countrycountry=address.getCountry();
if (null!=country ) {
Stringcode=country.getCode();
if (null!=code) {
code=code.toUpperCase();
            }
        }
    }
}

代码变得很冗长,难以维护。并且如果再新增加属性,将会增加更多的if判断。为了简化这个过程,我们来看看用 Optional  类是怎么做的。从创建和验证实例,到使用其不同的方法,并与其它返回相同类型的方法相结合,下面是见证 Optional  奇迹的时刻。

二、创建Optional对象

1. 创建包含空值的Optional

Optional.empty();

Optional.of()/Optional.ofNullable()

你可以使用Optional.of()或ofNullable()方法创建Optional对象,两个方法的区别是,使用Optional.of()方法创建对象时,当参数为null时,调用get()方法,程序会抛出NullPointerException。如下图所示

image.png

使用Optional.ofNullable(),当参数为null时,程序会抛出java.util.NoSuchElementException: No value present 异常。如下图所示

image.png

三、获取Optional对象的值

1. get()方法

使用get()方法,此方法在值为null时,抛出异常

@TestpublicvoidgetOptionValue(){
Stringname="John";
Optional<String>opt=Optional.ofNullable(name);
System.out.println(opt.get());
    }

2. isPresent()

 判断是否有值,再进行后续操作

@TestpublicvoidgetOptionValue(){
Stringname="John";
Optional<String>opt=Optional.ofNullable(name);
if(opt.isPresent()){
System.out.println(opt.get());
        }
    }

3. ifPresent()

   判断是否有值再进行后续操作,接受一个Consumer(消费者) 参数,如果对象不是空的,就对执行传入的 Lambda 表达式

@TestpublicvoidgetOptionValue(){
Stringname="John";
Optional<String>opt=Optional.ofNullable(name);
opt.ifPresent(System.out::println );
    }

四、返回默认值

1. orElse()

orElse()方法,它的工作方式非常直接,如果有值则返回该值,否则返回传递给它的参数值。如下示例代码,如果name为null则返回"Sim",如果name不为空则直接返回name。

@TestpublicvoidgetOptionOrElse(){
Stringname=null;
Optional<String>opt=Optional.ofNullable(name);
StringnameStr=opt.orElse("Sim");
System.out.println(nameStr);
    }

2.orElseGet()

此方法略有不同。这个方法会在有值的时候返回值,如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果:

@TestpublicvoidgetOptionOrElseGet(){
Useruser=null;
Useruser2=newUser();
user2.setName("abc");
Useruser3=Optional.ofNullable(user).orElseGet(
                () ->user2);
System.out.println(user3);
    }

3.orElse和orElseGet区别

当Optional中对象为空是,两者没有区别都,返回默认值或供给函数提供的值。

当Optional中对象不为空,orElse仍然执行产生默认值的方法,如下图所示:

image.png

当Optional中对象不为空,orElseGet不会执行产生默认值的方法,如下图所示:

image.png

五、返回异常

1.orElseThrow()

当Optional对象值为空的时抛出异常,异常可以自定义。

@TestpublicvoidgetOptionOrElseThrow(){
Useruser2=null;
//当user2为空时,抛出异常Useruser3=Optional.ofNullable(user2).orElseThrow(
                () ->newIllegalArgumentException() );
    }

六、转换值

1.map方法

map方法接收一个function接口,并且把返回值包装成Optional对象,使对返回值进行链式调用的操作成为可能,如下代码所示,调用map后,可紧着调用orElse

@TestpublicvoidtestMap(){
Useruser2=newUser();
user2.setName("Lisa");
user2.setAddress("上海");
Stringaddress=Optional.ofNullable(user2).
map(u->u.getAddress()).orElse("北京");
System.out.println(address);
    }

2.flatMap

map方法接收一个function接口,返回值直接是一个Optional对象,不需要进行重新包装。

publicOptional<String>getCode(){
returnOptional.ofNullable(code);
    } 
@TestpublicvoidtestFlatMap(){
Useruser2=newUser();
user2.setName("Lisa");
user2.setAddress("上海");
Stringcode=Optional.ofNullable(user2).flatMap(u->u.getCode()).orElse("北京");
System.out.println(code);
    }

七、过滤值

Optional  类也提供了按条件“过滤”值的方法,filter() 接受一个 Predicate 参数,返回测试结果为 true 的值。如果测试结果为 false,会返回一个空的 Optional。

@TestpublicvoidtestFilter() {
Useruser=newUser();
user.setEmail("anna@gmail.com");
Optional<User>result=Optional.ofNullable(user)
                .filter(u->StringUtils.isNotEmpty(u.getEmail()) &&u.getEmail().contains("@"));
System.out.println(result);
    }

八、怎么使用Optional

1.使用场景

Optional 主要用作返回类型。在获取到这个类型的实例后,如果它有值,你可以取得这个值,否则可以进行一些替代行为。

Optional 类有一个非常有用的用例,就是将其与流或其它返回 Optional 的方法结合,以构建流畅的API。

2.不适合使用场景

Optional 不是 Serializable。因此,它不应该用作类的字段。如果你需要序列化的对象包含 Optional 值,Jackson 库支持把 Optional 当作普通对象。也就是说,Jackson 会把空对象看作 null,而有值的对象则把其值看作对应域的值。这个功能在 jackson-modules-java8 项目中。

它在另一种情况下也并不怎么有用,就是在将其类型用作方法或构建方法的参数时,这样做会让代码变得复杂,完全没有必要。比如以下代码

Useruser=newUser(23, "Lisa", Optional.empty());

九、总结

Optional主要用来解决空指针异常,结合Stream流及Lambda表达式,使应用程序更加优化及健壮。


相关文章
|
2月前
|
安全 Java 开发者
告别NullPointerException:拥抱Java Optional
告别NullPointerException:拥抱Java Optional
|
25天前
|
存储 Oracle Java
java零基础学习者入门课程
本课程为Java零基础入门教程,涵盖环境搭建、变量、运算符、条件循环、数组及面向对象基础,每讲配示例代码与实践建议,助你循序渐进掌握核心知识,轻松迈入Java编程世界。
216 0
|
2月前
|
Java API 容器
Java基础学习day08-2
本节讲解Java方法引用与常用API,包括静态、实例、特定类型方法及构造器引用的格式与使用场景,并结合代码示例深入解析。同时介绍String和ArrayList的核心方法及其实际应用。
144 1
|
1月前
|
IDE Java 编译器
java编程最基础学习
Java入门需掌握:环境搭建、基础语法、面向对象、数组集合与异常处理。通过实践编写简单程序,逐步深入学习,打牢编程基础。
165 0
|
1月前
|
安全 Java 容器
告别繁琐判空:Optional让你的Java代码更优雅
告别繁琐判空:Optional让你的Java代码更优雅
|
1月前
|
安全 Java 容器
告别空指针噩梦:Optional让Java代码更优雅
告别空指针噩梦:Optional让Java代码更优雅
331 94
|
1月前
|
安全 Java 开发者
告别NullPointerException:掌握Java Optional的精髓
告别NullPointerException:掌握Java Optional的精髓
|
1月前
|
负载均衡 Java API
grpc-java 架构学习指南
本指南系统解析 grpc-java 架构,涵盖分层设计、核心流程与源码结构,结合实战路径与调试技巧,助你从入门到精通,掌握高性能 RPC 开发精髓。
178 7
|
2月前
|
Java
Java基础学习day08-作业
本作业涵盖Java中Lambda表达式的应用,包括Runnable与Comparator接口的简化实现、自定义函数式接口NumberProcessor进行加减乘及最大值操作,以及通过IntProcessor处理整数数组,实现遍历、平方和奇偶判断等功能,强化函数式编程实践。
66 5
|
2月前
|
Java 程序员
Java基础学习day08
本节讲解Java中的代码块(静态与实例)及其作用,深入介绍内部类(成员、静态、局部及匿名)的定义与使用,并引入函数式编程思想,重点阐述Lambda表达式及其在简化匿名内部类中的应用。
125 5