千家信息网

Java 8 Optional如何优雅地避免NPE

发表于:2025-01-25 作者:千家信息网编辑
千家信息网最后更新 2025年01月25日,这篇文章给大家介绍Java 8 Optional如何优雅地避免NPE,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。空指针异常(NullPointException,简称 NPE)
千家信息网最后更新 2025年01月25日Java 8 Optional如何优雅地避免NPE

这篇文章给大家介绍Java 8 Optional如何优雅地避免NPE,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

空指针异常(NullPointException,简称 NPE)可以说是所有 Java 程序员都遇到过的一个异常,虽然 Java 从设计之初就力图让程序员脱离指针的苦海,但是指针确实是实际存在的,而 Java 设计者也只能是让指针在 Java 语言中变得更加简单易用,而不能完全剔除,所以才有了常见对的关键字 null。

避免使用 null 检查

空指针异常是一个运行时异常,对于这一类异常,如果没有明确的处理方式,那么最佳实践在于让程序早点挂掉。当异常真的发生的时候,处理方式也很简单,在存在异常的地方添加一个 if 语句判定即可。比如下面的代码:

public String bindUserToRole(User user) {    if (user == null) {        return;    }    String roleId = user.getRoleId();    if (roleId == null) {        return;    }    Role = roleDao.findOne(roleId);    if (role != null) {        role.setUserId(user.getUserId());        roleDao.save(role);    }}

但是这样的应对方式会让程序出现越来越多的 null 判定,一个良好的程序设计,应该让代码中尽量少出现 null 关键字,因此 Java 8 引入 Optional 类来避免 NPE 问题,同时也提升了代码的美观度。但并不是对 null 关键字的一种替代,而是对于 null 判定提供了一种更加优雅的实现,从而避免 NPE 问题。

Optional 类

为了更好的解决和避免常见的 NPE 问题,Java 8 中引入了一个新的类 java.util.Optional,Optional 值可以为 null,如果值存在,调用 isPresent() 方法返回 true,调用 get() 方法可以获取值。

创建 Optional 对象

Optional 类提供类三个方法用于实例化一个 Optional 对象,它们分别为 empty()、of()、ofNullable(),这三个方法都是静态方法,可以直接调用。

empty() 方法用于创建一个没有值的Optional对象:

Optional emptyOpt = Optional.empty();

empty() 方法创建的对象没有值,如果对 emptyOpt 变量调用 isPresent() 方法会返回 false,调用 get() 方法抛出 NPE 异常。

of() 方法使用一个非空的值创建Optional对象:

String str = "Hello World";Optional notNullOpt = Optional.of(str);

ofNullable() 方法接收一个可以为null的值:

Optional nullableOpt = Optional.ofNullable(str);

如果 str 的值为 null,得到的 nullableOpt 是一个没有值的 Optional 对象。

获取 Optional 对象中的值

如果我们要获取 User 对象中的 roleId 属性值,常见的方式是直接获取:

String roleId = null;if (user != null) {    roleId = user.getRoleId();}

使用 Optional 中提供的 map() 方法可以更简单地实现:

Optional userOpt = Optional.ofNullable(user);Optional roleIdOpt = userOpt.map(User::getRoleId);

使用 orElse()方法获取值

Optional 类还包含其他方法用于获取值,这些方法分别为:

  • orElse():如果有值就返回,否则返回一个给定的值作为默认值

  • orElseGet():与 orElse() 方法作用类似,区别在于生成默认值的方式不同。该方法接受一个 Supplier 函数式接口参数,用于生成默认值

  • orElseThrow():与前面介绍的 get() 方法类似,当值为 null 时调用这两个方法都会抛出 NPE 异常,区别在于该方法可以指定抛出的异常类型

下面来看看这三个方法的具体用法:

String str = "Hello World";Optional strOpt = Optional.of(str);String orElseResult = strOpt.orElse("Hello BeiJing");String orElseGet = strOpt.orElseGet(() -> "Hello BeiJing");String orElseThrow = strOpt.orElseThrow(        () -> new IllegalArgumentException("Argument 'str' cannot be null or blank."));

此外,Optional 类还提供了一个 ifPresent() 方法,该方法接收一个 Consumer 函数式接口,一般用于将信息打印到控制台:

Optional strOpt = Optional.of("Hello World");strOpt.ifPresent(System.out::println);

使用 filter() 方法过滤

filter() 方法可用于判断 Optional 对象是否满足给定条件,一般用于条件过滤:

Optional optional = Optional.of("wupx94@qq.com");optional = optional.filter(str -> str.contains("wupx"));

在上面的代码中,如果 filter() 方法中的 Lambda 表达式成立,filter() 方法会返回当前 Optional 对象值,否则,返回一个值为空的 Optional 对象。

关于 Optional 使用建议:

  • 尽量避免在程序中直接调用 Optional 对象的 get() 和 isPresent() 方法

  • 避免使用 Optional 类型声明实体类的属性

Optional 实践

上面提到创建 Optional 对象有三个方法,empty() 方法比较简单,主要是 of() 和 ofNullable() 方法。当你确定一个对象不可能为 null 的时候,应该使用 of() 方法,否则,尽可能使用 ofNullable() 方法,比如:

public static void method(Role role) {    // 当Optional的值通过常量获得或者通过关键字 new 初始化,可以直接使用 of() 方法    Optional strOpt = Optional.of("Hello World");    Optional userOpt = Optional.of(new User());    // 方法参数中role值不确定是否为null,使用 ofNullable() 方法创建    Optional roleOpt = Optional.ofNullable(role);}

orElse() 方法的使用

return str != null ? str : "Hello World"

上面的代码表示判断字符串 str 是否为空,不为空就返回,否则,返回一个常量。使用 Optional 类可以表示为:

return strOpt.orElse("Hello World")

简化 if-else

User user = ...if (user != null) {    String userName = user.getUserName();    if (userName != null) {        return userName.toUpperCase();    } else {        return null;    }} else {    return null;}

上面的代码可以简化成:

User user = ...Optional userOpt = Optional.ofNullable(user);return userOpt.map(User::getUserName)            .map(String::toUpperCase)            .orElse(null);

注意事项

Optional 是一个 final 类,未实现任何接口,Optional 不能序列化,不能作为类的字段(field),所以当我们在利用该类包装定义类的属性的时候,如果我们定义的类有序列化的需求,那么因为 Optional 没有实现 Serializable 接口,这个时候执行序列化操作就会有问题:

import java.util.Optional;import lombok.Data;@Datapublic class User implements Serializable {    private String name;    private String gender;    private Optional phone; // 不能序列化}

可以通过自己实现 getter 方法,使 Lomok 不自动生成,如下:

import java.util.Optional;import lombok.Data@Datapublic class User implements Serializable  {    private String name;    private String gender;    private String phone;    public Optional getPhone() {        return Optional.ofNullable(phone);    }}

Java 8 中 Optional 类可以让我们以函数式编程的方式处理 null 值,抛弃了 Java 8 之前需要嵌套大量 if-else 代码块,使代码可读性有了很大的提高,但是应尽量避免使用 Optional 类型声明实体类的属性。

关于Java 8 Optional如何优雅地避免NPE就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

方法 对象 代码 方式 程序 指针 三个 关键 关键字 属性 序列 接口 时候 问题 面的 优雅 函数 常见 类型 处理 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 日本软件开发的工资 电视可以下载网络安全吗 沃思互联网科技有限公司 河南计算机网络技术 网络安全进校园征文300 网赌棋牌软件开发 新建数据库监听器报错 杨浦区信息化软件开发价目表 国家网络安全手工小制作 湖南服务器机柜定做高档虚拟主机 网络安全设备产品认证目录 网络安全知识手抄报花边 四川品质软件开发服务有哪些 网络安全龙头股票成都 四川省财政专网网络安全接入规范 ad域管理服务器怎么上 哈尔滨租服务器软件开发 职高计算机网络技术培训 乡镇网络安全应急演练脚本 asp.net获取数据库 河南能源化工集团网络安全运维 奋斗软件开发 最好的软件开发与定制公司 数据库前端后台关系 mysql是什么数据库 数据库优化过程中 在数据库事务的可重复读级别下 专科计算机网络技术课表 东信软件开发有限公司 我的世界手机工业服务器火一点的
0