从 Java 8 引入的一个特性是 Optional 类。Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException) —— 每个 Java 程序员都非常了解的异常。本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。
of() 和 ofNullable()
如果是空of() 方法会抛出 NullPointerException,
当不确定对象为不为空的时候,可以用ofNullable,当对象是空的时会给一个empty。
// Optional.ofNullable -允许传递为 null 参数
Optional<Integer>a = Optional.ofNullable(value1);
// 0ptional.of - 如果传递的参数是 null,抛出异常 NullPointerException
Optional<Integer>b = Optional.of(value2);
get() 和ifPresent()
从 Optional 实例中取回实际值对象的方法之一是使用 get() 方法, 这个方法会在值为 null 的时候抛出异常。
Optional<string> stringOptional = Optional.of("张三");
System.out.printin(stringOptional.get());
要避免异常,你可以选择首先验证是否有值,检查是否有值的另一个选择是 ifPresent() 方法。该方法除了执行检查,还接受一个Consumer(消费者) 参数,如果对象不是空的,就对执行传入的 Lambda 表达式。
Optional<User> user = Optional.ofNullable(getUserById(id));
user.ifpresent(
u -> System.out.println("Username is: " + u.getUsername()));
orElse()和orElseGet()和orElseThrow()
Optional 类提供了 API 用以返回对象值,或者在对象为空的时候返回默认值。
这里你可以使用的第一个方法是 orElse(),它的工作方式非常直接,如果有值则返回该值,否则返回传递给它的参数值。
Optional<String> stringOptional = Optional.of("张三");
System.out.println(stringOptional.orElse("zhangsan")):
Optional<String> emptyOptional = Optional.enpty();
system.out.println(emptyOptional.orElse("李四"));
执行结果:张三、李四
第二个同类型的 API 是 orElseGet() —— 其行为略有不同。这个方法会在有值的时候返回值,如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果。
Optional<String> stringOptional = Optional.of(“张三”);
System.out.println(stringOptional.orElseGet(()-> "zhangsan"));
Optional<String>emptyOptional = Optional.empty();
System.out.println(emptyOptional.orElseGet(()-> "orElseGet"));
执行结果:张三、orElseGet
Optional 还定义了 orElseThrow() API —— 它会在对象为空的时候抛出异常,而不是返回备选的值,这个方法让我们有更丰富的语义,可以决定抛出什么样的异常,而不总是抛出 NullPointerException。
Optional<string> emptyOptional = Optional.empty();
System.out.println(emptyOptional.orElseThrow(CustomException::new));
private static class CustomException extends RuntimeException{
private static final long serialVersionuID = -4399699891687593264L;
public CustomException (){
super("自定义异常");
}
public CustomException(String message){
super(message);
}
map和flatMap
map()方法的参数为Function(函数式接口)对象,map()方法将Optional中的包装对象用Function函数进行运算,并包装成新的Optional对象。
public static Optional<Integer> getAge(Student student){
return Optional.ofNullable(student).map(u -> u.getAge());
}
和map()方法不同的是,flatMap的入参Function函数的返回值类型为Optional<U>
类型,而不是U类型,这样flatMap()能将一个二维的Optional对象映射成一个一维的对象。
public static Optional<Integer> getAge(Student student){
return Optional,ofNullable(student)
.flatMap(u -> Optional.ofullable(u.getAge()))
}
总结:
在使用 Optional 的时候需要考虑一些事情,以决定什么时候怎样使用它。
重要的一点是 Optional 不是 Serializable。因此,它不应该用作类的字段。
如果你需要序列化的对象包含 Optional 值,Jackson 库支持把 Optional 当作普通对象。也就是说,Jackson 会把空对象看作 null,而有值的对象则把其值看作对应域的值。它在另一种情况下也并不怎么有用,就是在将其类型用作方法或构建方法的参数时。这样做会让代码变得复杂,完全没有必要。
Optional 主要用作返回类型。在获取到这个类型的实例后,如果它有值,你可以取得这个值,否则可以进行一些替代行为。
Optional 类有一个非常有用的用例,就是将其与流或其它返回 Optional 的方法结合,以构建流畅的API。
Optional 是 Java 语言的有益补充 —— 它旨在减少代码中的 NullPointerExceptions,虽然还不能完全消除这些异常。
它也是精心设计,自然融入 Java 8 函数式支持的功能。
总的来说,这个简单而强大的类有助于创建简单、可读性更强、比对应程序错误更少的程序。