Java 8 Optional:优雅地避免 NPE java防止xss

createh52周前 (12-20)技术教程17

本篇文章将详细介绍 Optional 类,以及如何用它消除代码中的 null 检查。在开始之前首先来看下什么是 NPE,以及在 Java 8 之前是如何处理 NPE 问题的。

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

避免使用 null 检查

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

但是这样的应对方式会让程序出现越来越多的 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对象:

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

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

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

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

获取 Optional 对象中的值

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

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

使用 orElse()方法获取值

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

  • orElse():如果有值就返回,否则返回一个给定的值作为默认值
  • orElseGet():与 orElse() 方法作用类似,区别在于生成默认值的方式不同。该方法接受一个 Supplier 函数式接口参数,用于生成默认值
  • orElseThrow():与前面介绍的 get() 方法类似,当值为 null 时调用这两个方法都会抛出 NPE 异常,区别在于该方法可以指定抛出的异常类型

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

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

使用 filter() 方法过滤

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

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

关于 Optional 使用建议:

  • 尽量避免在程序中直接调用 Optional 对象的 get() 和 isPresent() 方法
  • 避免使用 Optional 类型声明实体类的属性

Optional 实践

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

orElse() 方法的使用

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

简化 if-else

上面的代码可以简化成:

注意事项

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

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

总结

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

相关文章

前端面试题(1):undefined和null的区别

寒冬来临,裁员的消息此起彼伏。现在准备面试肯定是有备无患,我准备了一系列前端面试的常见问题,和大家一起学习。不管你是不是有找工作的需求,多掌握一些肯定是有益无害。1.undefined和null有什么...

在Java中如果对象的引用被设置为null,垃圾收集器应当如何工作?

在Java中,如果在程序初始化之初就将一个对象的引用设置为NULL。那么JVM的垃圾回收机制该如何工作呢?是不是就会立即释放该对象所占用的内存呢?答案是否定的,将一个对象设置为NULL,垃圾回收机制并...

Java判空,Optional和工具类真香?还是if(obj == null)更靠谱?

背景描述最近在开发项目时,我遇到了一个需要从 Hyperlink 对象中获取 link 属性的小需求。这个过程中我需要判断 Hyperlink 对象是否为 null,以防止出现空指针异常。面对这种情况...

java.lang.NullPointerException空指针异常

NPE空指针异常出现的原因是什么?空指针异常应该是初学编程的同学遇到最多的一种异常,由于缺少编程经验,对引用数据类型的数据使用不恰当导致的异常。空指针就是空引用,java空指针异常就是引用变量本身为n...

关于Java String 类型转换时null的问题

开发中经常遇到从集合类List、Map中取出数据转换为String的问题,这里如果处理不好,经常会遇到空指针异常java.lang.NullPointerException,在此总结一下常用转换为St...

Java中当对象不再使用时,不赋值为null会导致什么后果?

前言许多Java开发者都曾听说过“不使用的对象应手动赋值为null“这句话,而且好多开发者一直信奉着这句话;问其原因,大都是回答“有利于GC更早回收内存,减少内存占用”,但再往深入问就回答不出来了。鉴...