首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Optional 类解决空指针异常

Optional 类解决空指针异常

作者头像
BUG弄潮儿
发布2021-05-17 15:31:15
发布2021-05-17 15:31:15
99900
代码可运行
举报
文章被收录于专栏:JAVA乐园JAVA乐园
运行总次数:0
代码可运行

前言

空指针异常是导致 Java 应用程序失败的最常见原因。以前,为了解决空指针异常,Google 公司著名的 Guava 项目引入了 Optional 类,Guava 通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到 Google Guava 的启发,Optional 类已经成为 Java8 类库的一部分。Optional 实际上是个容器:它可以保存类型 T 的值,或者仅仅保存 null。Optional 提供很多有用的方法,这样我们就不用显式进行空值检测。

Optional 范例

构造方式

Optional 的三种构造方式:Optional.of(obj),Optional.ofNullable(obj) 和 Optional.empty()。

  • Optional.of(),依据一个非空值创建 Optional
代码语言:javascript
代码运行次数:0
运行
复制
// 如果 car 是一个 null, 这段代码会立即抛出 
// NullPointException, 而不是等到试图访问 car 的属性值时才返回一个错误.
Optional<Integer> optCar = Optional.of(car);
  • Optional.ofNullable(),可接受 null 的 Optional(实现序列化的域模型时使用)
代码语言:javascript
代码运行次数:0
运行
复制
// 创建一个允许 null 值的 Optional 对象, 
// 如果 car 是 null, 那么得到的 Optional 对象就是个空对象.
Optional<Integer> optCar = Optional.ofNullable(car);
  • Optional.empty(),所有 null 包装成的 Optional 对象。
代码语言:javascript
代码运行次数:0
运行
复制
// 声明一个空的 Optional
Optional<Integer> empty = Optional.empty();

isPresent()/ifPresent(Consumer consumer)

isPresent(),判断值是否存在。

代码语言:javascript
代码运行次数:0
运行
复制
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);

// isPresent 判断值是否存在
System.out.println(optional1.isPresent() == true);
System.out.println(optional2.isPresent() == false);

ifPresent(Consumer consumer):如果 option 对象保存的值不是 null,则调用 consumer 对象,否则不调用。

代码语言:javascript
代码运行次数:0
运行
复制
// 如果不是 null, 调用 Consumer; 如果 null, 不调用 Consumer
optional1.ifPresent(new Consumer<Integer>() {
    @Override
    public void accept(Integer t) {
        System.out.println("value is" + t);
    }
});

// Lambda 表达式写法
optional1.ifPresent(t -> System.out.println("value is" + t));

orElse(value)/orElseGet(Supplier supplier)

orElse(value):如果 optional 对象保存的值不是 null,则返回原来的值,否则返回 value。

代码语言:javascript
代码运行次数:0
运行
复制
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);

System.out.println(optional1.orElse(1000) == 1);// true
System.out.println(optional2.orElse(1000) == 1000);// true

orElseGet(Supplier supplier):功能与 orElse 一样,只不过 orElseGet 参数是一个对象,即无则由函数来产生。

代码语言:javascript
代码运行次数:0
运行
复制
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);

System.out.println(optional1.orElseGet(() -> {
    return 1000;
}) == 1);
// true

System.out.println(optional2.orElseGet(() -> {
    return 1000;
}) == 1000);
// true

orElseThrow()

orElseThrow():值不存在则抛出异常,存在则什么不做,有点类似 Guava 的 Precoditions。

代码语言:javascript
代码运行次数:0
运行
复制
Optional<Integer> optional = Optional.ofNullable(null);

optional.orElseThrow(() -> {
    throw new NullPointerException();
});

filter(Predicate)

filter(Predicate):判断 Optional 对象中保存的值是否满足 Predicate,并返回新的 Optional。

代码语言:javascript
代码运行次数:0
运行
复制
Optional<Integer> optional = Optional.ofNullable(1);

Optional<Integer> filter = optional.filter((a) -> a == 1);

map(Function)/flatMap(Function)

map(Function) 如果有值,则对其执行调用 mapping 函数得到返回值,否则返回空 Optional。如果返回值不为 null,则创建包含 mapping 返回值的 Optional 作为 map 方法返回值,否则返回空 Optional。

代码语言:javascript
代码运行次数:0
运行
复制
Optional<String> upperName = name.map((value) -> value.toUpperCase());
System.out.println(upperName.orElse("No value found"));

flatMap(Function) 如果有值,为其执行 mapping 函数返回 Optional 类型返回值,否则返回空 Optional。flatMap 与 map(Funtion)方法类似,区别在于 flatMap 中的 mapper 返回值必须是 Optional。调用结束时,flatMap 不会对结果用 Optional 封装。[P.S. 参考博文 [3]:Cascading Optional Objects Using the flatMap Method]

代码语言:javascript
代码运行次数:0
运行
复制
upperName = name.flatMap((value) -> Optional.of(value.toUpperCase()));
System.out.println(upperName.orElse("No value found"));

Optional 类的链式方法

错误示范 / 正确示范

  • 示范(一)
代码语言:javascript
代码运行次数:0
运行
复制
// ** 错误示范
Optional<User> user = ...... 
if (user.isPresent()) {
    return user.getOrders();
} else {
    return Collections.emptyList();
}
// 二者实质上是没有任何分别
User user = .....
if (user != null) {
    return user.getOrders();
} else {
    return Collections.emptyList();
}

// ** 正确示范
return user.map(u -> u.getOrders()).orElse(Collections.emptyList())

// map 是可能无限级联的, 比如再深一层, 获得用户名的大写形式
return user.map(u -> u.getUsername())
           .map(name -> name.toUpperCase())
           .orElse(null);
  • 示范(二)
代码语言:javascript
代码运行次数:0
运行
复制
// ** 错误示范
String version = "UNKNOWN";
if(computer != null){
  Soundcard soundcard = computer.getSoundcard();
  if(soundcard != null){
    USB usb = soundcard.getUSB();
    if(usb != null){
      version = usb.getVersion();
    }
  }
}

// ** 正确示范
String version = computer.map(Computer::getSoundcard)
                  .map(Soundcard::getUSB)
                  .map(USB::getVersion)
                  .orElse("UNKNOWN");

参考博文

[1]. Java 8 Optional 类深度解析 [2]. 使用 Java8 Optional 的正确姿势 [3]. Tired of Null Pointer Exceptions? Consider Using Java SE 8’s Optional!

代码语言:javascript
代码运行次数:0
运行
复制
source:https://morning-pro.github.io/archives/8eb6feba.html
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-05-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 BUG弄潮儿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • Optional 范例
    • 构造方式
    • isPresent()/ifPresent(Consumer consumer)
    • orElse(value)/orElseGet(Supplier supplier)
    • orElseThrow()
    • filter(Predicate)
    • map(Function)/flatMap(Function)
  • Optional 类的链式方法
    • 错误示范 / 正确示范
  • 参考博文
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档