Optional
如果一个方法返回一个Object,那么我们在使用的时候总是要判断一下返回的结果是否为空,一般是这样的形式:
if (a != null) {
//do something...
}但是简单的情况还好,如果复杂的情况下每一个都要去检查非常麻烦,而且写出来的代码也不好看、很臃肿,但是如果不检查就很容易遇到NullPointerException, Java8中的Optional就是为此而设计的。
Optional一般使用在方法的返回值中,如果使用Optional来包装方法的返回值,这就表示方法的返回值可能为null,需要使用Optional提供的方法来检查,如果为null,还可以提供一个默认值。
//创建Optional对象
Optional<String> opt = Optional.empty();
//依据一个非空值创建Optional
Optional<String> opt = Optional.of("hello");
//可接受null的Optional
Optional<String> opt = Optional.ofNullable(null);除了以上这些方法外,Optional还提供了以下方法:
| 方法 | 描述 |
|---|---|
| empty | 返回一个空的Optional实例 |
| filter | 如果值存在并且满足提供的谓词,就返回包括该值的Optional对象;否则返回一个空的Optional对象 |
| flatMap | 如果值存在,就对该值执行提供的mapping函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象 |
| get | 如果该值存在,将该值用Optional封装返回,否则抛出一个NoSuchElementException异常 |
| ifPresent | 如果值存在,就执行使用该值的方法调用,否则返回false |
| isPresent | 如果值存在就返回true,否则返回false |
| map | 如果值存在,就对该值执行提供的mapping函数调用 |
| of | 将指定值用Optional封装之后返回,如果该值为null,抛出一个NullPointerException异常 |
| ofNullable | 将指定值用Optional封装之后返回,如果该值为null,则返回一个空的Optional对象 |
| orElse | 如果有值则将其返回,否则返回一个默认值 |
| orElseGet | 如果有值则将其返回,否则返回一个由指定的Supplier接口生成的值 |
| orElseThrow | 如果有值则将其返回,否则抛出一个由指定的Supplier接口生成的异常 |
of
为非null的值创建一个Optional。通过工厂方法创建Optional类。注意:创建对象时传入的参数不能为null。否则抛出NullPointerException 。
//调用工厂方法创建Optional实例
Optional<String> name = Optional.of("Name");
//传入参数为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()) {
System.out.println(name.get()); // 输出结果
}示例2
// 推荐
user.ifPresent(System.out::println);
// 不推荐
if (user.isPresent()) {
System.out.println(user.get());
}ifPresent
如果Optional实例有值则为其调用consumer,否则不做处理
要理解ifPresent方法,首先需要了解Consumer类。简答地说,Consumer类包含一个抽象方法。该抽象方法对传入的值进行处理,但没有返回值。Java8支持不用接口直接通过lambda表达式传入参数。
如果Optional实例有值,调用ifPresent()可以接受接口段或lambda表达式。类似下面的代码:
// ifPresent方法接受lambda表达式作为参数。
// lambda表达式对Optional的值调用consumer进行处理。
Optional<String> name = Optional.of("Name");
name.ifPresent(value -> System.out.println("The length of the value is: " + value.length()));
System.out.println(name.get());
// 运行结果
The length of the value is: 4
Name示例2
Optional<Student> student = Optional.of(new Student("Anson",100));
System.out.println(student.get().getName()); // Anson
student.ifPresent(stu->stu.setName("听风"));
System.out.println(student.get().getName()); // 听风get
如果Optional有值则将其返回,否则抛出NoSuchElementException。
Optional empty = Optional.ofNullable(null); System.out.println(empty.get()); // 异常内容 Exception in thread "main" java.util.NoSuchElementException: No value present
orElse 存在即返回, 无则提供默认值
如果有值则将其返回,否则返回指定的其它值。
如果Optional实例有值则将其返回,否则返回orElse方法传入的参数。示例如下:
Optional<String> name = Optional.of("听风");
Optional<String> empty = Optional.empty();
// 如果值不为null,orElse方法返回Optional实例的值。
// 如果为null,返回传入的消息。
System.out.println(empty.orElse("There is no value present!")); // There is no value present!
System.out.println(name.orElse("There is some value!")); // 听风orElseGet 存在即返回, 无则由函数来产生
orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。示例如下:
return user.orElseGet(() -> fetchAUserFromDatabase()); // 而不要 return user.isPresent() ? user: fetchAUserFromDatabase();
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定义如下:
public 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
如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。
map方法用来对Optional实例的值执行一系列操作。通过一组实现了Function接口的lambda表达式传入操作。
map方法示例如下:
// map方法执行传入的lambda表达式参数对Optional实例的值进行修改。为lambda表达式的返回值创建新的Optional实例作为map方法的返回值。
Optional<String> name = Optional.of("hello");
Optional<String> upperName = name.map(value -> value.toUpperCase());
System.out.println(upperName.orElse("No value found")); // HELLOflatMap
如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper返回值必须是Optional。调用结束时,flatMap不会对结果用Optional封装。
flatMap方法与map方法类似,区别在于mapping函数的返回值不同。map方法的mapping函数返回值可以是任何类型T,而flatMap方法的mapping函数必须是Optional。
参照map函数,使用flatMap重写的示例如下:
Optional<String> name = Optional.of("hello");
Optional<String> upperName = name.flatMap(value -> Optional.of(value.toUpperCase()));
System.out.println(upperName.orElse("No value found")); // HELLOfilter
filter个方法通过传入限定条件对Optional实例的值进行过滤。
描述:如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。
读到这里,可能你已经知道如何为filter方法传入一段代码。是的,这里可以传入一个lambda表达式。对于filter函数我们应该传入实现了Predicate接口的lambda表达式。
现在我来看看filter的各种用法,下面的示例介绍了满足限定条件和不满足两种情况:
Optional<String> name = Optional.of("helloWorld");
Optional<String> longName = name.filter(v -> v.length() > 6);
System.out.println(longName.orElse("名字长度小于6")); // 输出:helloWorld
Optional<String> anotherName = Optional.of("程序喵");
Optional<String> shortName = anotherName.filter(v -> v.length() > 6);
System.out.println(shortName.orElse("名字长度小于6")); // 输出:名字长度小于6Map其他示例
当 user.isPresent() 为真, 获得它关联的 orders , 为假则返回一个空集合时, 我们用上面的 orElse , orElseGet 方法都乏力时, 那原本就是 map 函数的责任, 我们可以这样一行
return user.map(u -> u.getOrders()).orElse(Collections.emptyList())
//上面避免了我们类似 Java 8 之前的做法
if(user.isPresent()) {
return user.get().getOrders();
} else {
return Collections.emptyList();
}map 是可能无限级联的, 比如再深一层, 获得用户名的大写形式
return user.map(u -> u.getUsername()) .map(name -> name.toUpperCase()) .orElse(null);
这要搁在以前, 每一级调用的展开都需要放一个 null 值的判断
User user = .....
if(user != null) {
String name = user.getUsername();
if(name != null) {
return name.toUpperCase();
} else {
return null;
}
} else {
return null;
}针对这方面 Groovy 提供了一种安全的属性/方法访问操作符 ?.
user?.getUsername()?.toUpperCase();
Swift 也有类似的语法, 只作用在 Optional 的类型上.
未经允许请勿转载:程序喵 » Java8新特性:Optional类深度解析
程序喵