- Java 8:Lambda 序列化?
- Java 8 lambda 最佳实践
- Java 8 lambda 表达式 10 个示例
- Java8 lambda 表达式 10 个示例
- Java8 Lambda 表达式和流操作如何让你的代码变慢 5 倍
- Java8:Lambda 表达式增强版 Comparator 和排序
- Java 8 LongAdders:管理并发计数器的正确方式
- Java 8 Optional 类深度解析
- Java8 中的 java.util.Random 类
- Java8 中的简易并发
- Java8 学习:Lambda 表达式、Stream API 和功能性接口 — 教程、资源、书籍和实例
- Java8 并发教程:Threads 和 Executors
- Java 8 新特性之旅:使用 Stream API 处理集合
- Java 8 新特性探究(一)通往 lambda 之路_语法篇
- Java 8 新特性探究(六)泛型的目标类型推断
- Java 8 新特性探究(七)深入解析日期和时间-JSR310
- Java 8 新特性探究(八)精简的 JRE 详解
- Java 8 新特性探究(九)跟 OOM:Permgen 说再见吧
- 总结
- Java 8 新特性探究(十)StampedLock 将是解决同步问题的新宠
- Java 8 新特性探究(十一)Base64 详解
- Java 8 新特性探究(十二)Nashorn :新犀牛
- Java 8 新特性终极指南
- Java 8 新的时间日期库的 20 个使用示例
- Java8 日期时间(Date Time)API 指南
- Java8 本地缓存
- Java 8 的 default 方法能做什么?不能做什么?
- Java 8 的 6 个问题
- Java 8 简明教程
- Java8 集合中的 Lambda 表达式
- Java SE 8 新的时间和日期 API
- 在 Java 8 下更好地利用枚举
- 在 Java 8 中避免 Null 检查
- 鲜为人知的 Java8 特性:泛化目标类型推断
Java 8 Optional 类深度解析
身为一名 Java 程序员,大家可能都有这样的经历:调用一个方法得到了返回值却不能直接将返回值作为参数去调用别的方法。我们首先要判断这个返回值是否为 null,只有在非空的前提下才能将其作为其他方法的参数。这正是一些类似 Guava 的外部 API 试图解决的问题。一些 JVM 编程语言比如 Scala、Ceylon 等已经将对在核心 API 中解决了这个问题。在我的 前一篇文章 中,介绍了 Scala 是如何解决了这个问题。
新版本的 Java,比如 Java 8 引入了一个新的 Optional 类。Optional 类的 Javadoc 描述如下:
这是一个可以为 null 的容器对象。如果值存在则 isPresent() 方法会返回 true,调用 get() 方法会返回该对象。
本文会逐个探讨 Optional 类包含的方法,并通过一两个示例展示如何使用。
of
为非 null 的值创建一个 Optional。
of 方法通过工厂方法创建 Optional 类。需要注意的是,创建对象时传入的参数不能为 null。如果传入参数为 null,则抛出 NullPointerException 。
//调用工厂方法创建 Optional 实例
Optional<String> name = Optional.of("Sanaulla");
//传入参数为 null,抛出 NullPointerException.
Optional<String> someNull = Optional.of(null);
ofNullable
为指定的值创建一个 Optional,如果指定的值为 null,则返回一个空的 Optional。
ofNullable 与 of 方法相似,唯一的区别是可以接受参数为 null 的情况。示例如下:
//下面创建了一个不包含任何值的 Optional 实例
//例如,值为'null'
Optional empty = Optional.ofNullable(null);
isPresent
非常容易理解
如果值存在返回 true,否则返回 false。
类似下面的代码:
//isPresent 方法用来检查 Optional 实例中是否包含值
if (name.isPresent()) {
//在 Optional 实例内调用 get() 返回已存在的值
System.out.println(name.get());//输出 Sanaulla
}
get
如果 Optional 有值则将其返回,否则抛出 NoSuchElementException。
上面的示例中,get 方法用来得到 Optional 实例中的值。下面我们看一个抛出 NoSuchElementException 的例子:
//执行下面的代码会输出:No value present
try {
//在空的 Optional 实例上调用 get(),抛出 NoSuchElementException
System.out.println(empty.get());
} catch (NoSuchElementException ex) {
System.out.println(ex.getMessage());
}
ifPresent
如果 Optional 实例有值则为其调用 consumer,否则不做处理
要理解 ifPresent 方法,首先需要了解 Consumer 类 。简答地说,Consumer 类包含一个抽象方法。该抽象方法对传入的值进行处理,但没有返回值。 Java8 支持不用接口直接通过 lambda 表达式 传入参数。
如果 Optional 实例有值,调用 ifPresent() 可以接受接口段或 lambda 表达式。类似下面的代码:
//ifPresent 方法接受 lambda 表达式作为参数。
//lambda 表达式对 Optional 的值调用 consumer 进行处理。
name.ifPresent((value) -> {
System.out.println("The length of the value is: " + value.length());
});
orElse
如果有值则将其返回,否则返回指定的其它值。
如果 Optional 实例有值则将其返回,否则返回 orElse 方法传入的参数。示例如下:
//如果值不为 null,orElse 方法返回 Optional 实例的值。
//如果为 null,返回传入的消息。
//输出:There is no value present!
System.out.println(empty.orElse("There is no value present!"));
//输出:Sanaulla
System.out.println(name.orElse("There is some value!"));
orElseGet
orElseGet 与 orElse 方法类似,区别在于得到的默认值。orElse 方法将传入的字符串作为默认值,orElseGet 方法可以接受 Supplier 接口 的实现用来生成默认值。示例如下:
//orElseGet 与 orElse 方法类似,区别在于 orElse 传入的是默认值,
//orElseGet 可以接受一个 lambda 表达式生成默认值。
//输出:Default Value
System.out.println(empty.orElseGet(() -> "Default Value"));
//输出:Sanaulla
System.out.println(name.orElseGet(() -> "Default Value"));
orElseThrow
如果有值则将其返回,否则抛出 supplier 接口创建的异常。
在 orElseGet 方法中,我们传入一个 Supplier 接口 。然而,在 orElseThrow 中我们可以传入一个 lambda 表达式或方法,如果值不存在来抛出异常。示例如下:
try {
//orElseThrow 与 orElse 方法类似。与返回默认值不同,
//orElseThrow 会抛出 lambda 表达式或方法生成的异常
empty.orElseThrow(ValueAbsentException::new);
} catch (Throwable ex) {
//输出: No value present in the Optional instance
System.out.println(ex.getMessage());
}
ValueAbsentException 定义如下:
class ValueAbsentException extends Throwable {
public ValueAbsentException() {
super();
}
public ValueAbsentException(String msg) {
super(msg);
}
@Override
public String getMessage() {
return "No value present in the Optional instance";
}
}
map
map 方法文档说明如下:
如果有值,则对其执行调用 mapping 函数得到返回值。如果返回值不为 null,则创建包含 mapping 返回值的 Optional 作为 map 方法返回值,否则返回空 Optional。
map 方法用来对 Optional 实例的值执行一系列操作。通过一组实现了 Function 接口的 lambda 表达式传入操作。如果你不熟悉 Function 接口,可以参考我的 这篇博客 。map 方法示例如下:
//map 方法执行传入的 lambda 表达式参数对 Optional 实例的值进行修改。
//为 lambda 表达式的返回值创建新的 Optional 实例作为 map 方法的返回值。
Optional<String> upperName = name.map((value) -> value.toUpperCase());
System.out.println(upperName.orElse("No value found"));
flatMap
如果有值,为其执行 mapping 函数返回 Optional 类型返回值,否则返回空 Optional。flatMap 与 map(Funtion)方法类似,区别在于 flatMap 中的 mapper 返回值必须是 Optional。调用结束时,flatMap 不会对结果用 Optional 封装。
flatMap 方法与 map 方法类似,区别在于 mapping 函数的返回值不同。map 方法的 mapping 函数返回值可以是任何类型 T,而 flatMap 方法的 mapping 函数必须是 Optional。
参照 map 函数,使用 flatMap 重写的示例如下:
//flatMap 与 map(Function)非常类似,区别在于传入方法的 lambda 表达式的返回类型。
//map 方法中的 lambda 表达式返回值可以是任意类型,在 map 函数返回之前会包装为 Optional。
//但 flatMap 方法中的 lambda 表达式返回值必须是 Optionl 实例。
upperName = name.flatMap((value) -> Optional.of(value.toUpperCase()));
System.out.println(upperName.orElse("No value found"));//输出 SANAULLA
filter
filter 个方法通过传入限定条件对 Optional 实例的值进行过滤。文档描述如下:
如果有值并且满足断言条件返回包含该值的 Optional,否则返回空 Optional。
读到这里,可能你已经知道如何为 filter 方法传入一段代码。是的,这里可以传入一个 lambda 表达式。对于 filter 函数我们应该传入实现了 Predicate 接口的 lambda 表达式。如果你不熟悉 Predicate 接口,可以参考 这篇文章 。
现在我来看看 filter 的各种用法,下面的示例介绍了满足限定条件和不满足两种情况:
//filter 方法检查给定的 Option 值是否满足某些条件。
//如果满足则返回同一个 Option 实例,否则返回空 Optional。
Optional<String> longName = name.filter((value) -> value.length() > 6);
System.out.println(longName.orElse("The name is less than 6 characters"));//输出 Sanaulla
//另一个例子是 Optional 值不满足 filter 指定的条件。
Optional<String> anotherName = Optional.of("Sana");
Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);
//输出:name 长度不足 6 字符
System.out.println(shortName.orElse("The name is less than 6 characters"));
以上,我们介绍了 Optional 类的各个方法。下面通过一个完整的示例对用法集中展示:
public class OptionalDemo {
public static void main(String[] args) {
//创建 Optional 实例,也可以通过方法返回值得到。
Optional<String> name = Optional.of("Sanaulla");
//创建没有值的 Optional 实例,例如值为'null'
Optional empty = Optional.ofNullable(null);
//isPresent 方法用来检查 Optional 实例是否有值。
if (name.isPresent()) {
//调用 get() 返回 Optional 值。
System.out.println(name.get());
}
try {
//在 Optional 实例上调用 get() 抛出 NoSuchElementException。
System.out.println(empty.get());
} catch (NoSuchElementException ex) {
System.out.println(ex.getMessage());
}
//ifPresent 方法接受 lambda 表达式参数。
//如果 Optional 值不为空,lambda 表达式会处理并在其上执行操作。
name.ifPresent((value) -> {
System.out.println("The length of the value is: " + value.length());
});
//如果有值 orElse 方法会返回 Optional 实例,否则返回传入的错误信息。
System.out.println(empty.orElse("There is no value present!"));
System.out.println(name.orElse("There is some value!"));
//orElseGet 与 orElse 类似,区别在于传入的默认值。
//orElseGet 接受 lambda 表达式生成默认值。
System.out.println(empty.orElseGet(() -> "Default Value"));
System.out.println(name.orElseGet(() -> "Default Value"));
try {
//orElseThrow 与 orElse 方法类似,区别在于返回值。
//orElseThrow 抛出由传入的 lambda 表达式/方法生成异常。
empty.orElseThrow(ValueAbsentException::new);
} catch (Throwable ex) {
System.out.println(ex.getMessage());
}
//map 方法通过传入的 lambda 表达式修改 Optonal 实例默认值。
//lambda 表达式返回值会包装为 Optional 实例。
Optional<String> upperName = name.map((value) -> value.toUpperCase());
System.out.println(upperName.orElse("No value found"));
//flatMap 与 map(Funtion)非常相似,区别在于 lambda 表达式的返回值。
//map 方法的 lambda 表达式返回值可以是任何类型,但是返回值会包装成 Optional 实例。
//但是 flatMap 方法的 lambda 返回值总是 Optional 类型。
upperName = name.flatMap((value) -> Optional.of(value.toUpperCase()));
System.out.println(upperName.orElse("No value found"));
//filter 方法检查 Optiona 值是否满足给定条件。
//如果满足返回 Optional 实例值,否则返回空 Optional。
Optional<String> longName = name.filter((value) -> value.length() > 6);
System.out.println(longName.orElse("The name is less than 6 characters"));
//另一个示例,Optional 值不满足给定条件。
Optional<String> anotherName = Optional.of("Sana");
Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);
System.out.println(shortName.orElse("The name is less than 6 characters"));
}
}
上述代码输出如下:
Sanaulla
No value present
The length of the value is: 8
There is no value present!
Sanaulla
Default Value
Sanaulla
No value present in the Optional instance
SANAULLA
SANAULLA
Sanaulla
The name is less than 6 characters
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论