目录
- 简介
- 场景引入
- 方法说明
- 构造函数
- 创建Optional对象
- 使用map从Optional对象中提取和转换值
- 使用flatMap链接Optional对象
- 默认行为及解引用Optional对象1
- 默认行为及解引用Optional对象2
- 使用filter剔除特定的值
- 实战
- 总结
简介
optional类是java8中引入的针对NPE问题的一种优美处理方式,源码作者也希望以此替代null。
历史
1965年,英国一位名为Tony Hoare的计算机科学家在设计ALGOL W语言时提出了null引用的想法。Hoare选择null引用这种方式,“只是因为这种方法实现起来非常容易”。很多年后,他开始为自己曾经做过这样的决定而后悔不迭,把它称为“我价值百万的重大失误”。我们已经看到它带来的后果——程序员对对象的字段进行检查,判断它的值是否为期望的格式,最终却发现我们查看的并不是一个对象,而是一个空指针,它会立即抛出一个让人厌烦的NullPointerException异常[1]。
null带来的种种问题
NullPointerException是目前Java程序开发中最典型的异常。
它让你的代码充斥着深度嵌套的null检查,代码的可读性糟糕透顶。
null自身没有任何的语义,尤其是,它代表的是在静态类型语言中以一种错误的方式对缺失变量值的建模。
Java一直试图避免让程序员意识到指针的存在,唯一的例外是:null指针。
null并不属于任何类型,这意味着它可以被赋值给任意引用类型的变量。这会导致问题,原因是当这个变量被传递到系统中的另一个部分后,你将无法获知这个null变量最初的赋值到底是什么类型。
方案
汲取Haskell和Scala的灵感,Java 8中引入了一个新的类java.util.Optional。这是一个封装Optional值的类。举例来说,使用新的类意味着,如果你知道一个人可能有学校也可能没有,那么Student类内部的school变量就不应该声明为Schoold,遭遇某学生没有学校时把null引用赋值给它,而是应该像本篇那样直接将其声明为Optional类型。
场景引入
首先我们引入一个常见的两个场景
/**
* >1 引入,常规判断一个学生的学校是不是公立学校,判断是否成年
*/
public static boolean checkIsPublicV1(Student student) {
if (student != null) {
School school = student.getSchool();
if (school != null) {
return school.isPublicFlag();
}
}
throw new RuntimeException("参数异常");
}
public static String getAdultV1(Student student) {
if (student != null) {
int age = student.getAge();
if (age > 18) {
return student.getName();
}
}
return "无";
}
上述方式是我们常见的判读流程,optional就是针对每次空判断导致的代码欣赏性问题进行了一套解决方案
方法说明
![Java8中Optional类的使用说明_第1张图片](http://img.e-com-net.com/image/info11/0bcfa5143b0f4678a3dc810add33a470.png)
构造函数
源码
private final T value;
private Optional() {
this.value = null;
}
private Optional(T var1) {
this.value = Objects.requireNonNull(var1);
}
从源码可知,optional的构造器私有,不能直接创建,只能通过类中的其他静态方法创建,optional构造器支持一个泛型入参,且改参数不能为空
创建Optional对象
- 声明一个空的Optional: Optional empty()
- 依据一个非空值创建Optional: Optional of(T var0)
- 可接受null的Optional: Optional ofNullable(T var0)
源码
empty()源码
private static final Optional EMPTY = new Optional();
private Optional() {
this.value = null;
}
public static Optional empty() {
Optional var0 = EMPTY;
return var0;
}
从源码可知,optional类中维护了一个null值的对象,使用empty静态方法即可返回该空值对象
of(T var0)源码
public static Optional of(T var0) {
return new Optional(var0);
}
返回常见的有参构造对象,注意由于构造器要求入参不能为空,因此of方法的入参为空的话,依然会报NPE异常
ofNullable(T var0)源码
public static Optional ofNullable(T var0) {
return var0 == null ? empty() : of(var0);
}
这个方法是对of方法的补强,当ofNullable方法的入参不为空是正常返回构造对象,当入参为空时,返回一个空值的optional对象,而不会抛出异常。
ofNullable方法大部分场景优于of的使用。
null引用和Optional.empty()有什么本质的区别吗?从语义上,你可以把它们当作一回事儿,但是实际中它们之间的差别非常大:如果你尝试解引用一个null,一定会触发NullPointerException,不过使用Optional.empty()就完全没事儿,它是Op-tional类的一个有效对象,多种场景都能调用,非常有用。
举例
public static void testOptionalBuild() {
// 1. 无法直接new 'Optional()' has private access in 'java.util.Optional'
// Optional school = new Optional<>();
// 2. of构建非空和空对象(NullPointerException)
/*Optional o1 = Optional.of("test");
System.out.println(o1);
Optional