为了解决空指针的一些问题,特别是方法的返回中,可能存在返回有null值的时候可以使用
java.util.Optional
来处理变量;
使用Optional的好处
- 避免空指针异常,使用
Optional
的目的就是用来处理空指针异常 - 显示的检查
Null
情况,使用idea时,如果没有检查Optional
直接获取值编译器会提示错误 Optional
提供了一些便利的方法可以更方便的处理Null
的情况Optional
使用了函数式编程,简化代码,避免写过多的if,可读性(不擅长函数式编程的可能有争议,但是Java8都这么久了,这方面时值得花精力扩展的)
基本使用
基于JDK8
1.定义Optional对象
1.1 定义一个空的Optional对象
Optional<String> empty = Optional.empty();
1.2 将value对象包装成Optional,此时value不能为null否则会报错
String value = "test";
Optional<String> test = Optional.of(value);
// 当of封装的对象为null时,则会报错
Exception in thread "main" java.lang.NullPointerException
at java.util.Objects.requireNonNull(Objects.java:203)
at java.util.Optional.<init>(Optional.java:96)
at java.util.Optional.of(Optional.java:108)
at lean.sort.Solution.main(Solution.java:8)
1.3 对于可能为null的对象,包装是要使用’ofNullable’方法
String value1 = null;
Optional<String> test1 = Optional.ofNullable(value1);
2.获取Optional对象的值
2.1判断Optional是否为空,这是一个不常用的做法。
boolean present = test.isPresent();
2.2获取Optional中的值,这是一个不常用的做法。
一般在执行get方法之前需要手动执行isPresent()方法,idea会警告;
如果此时Optional是empty的话,会报错
String str = test.get();
2.3获取Optional的值,如果为空则返回其他值
orElse()
方法会在 Optional 对象不为空时直接返回它所持有的对象,否则,它会返回传入的默认值。
orElseGet()
方法的参数是一个 Supplier 类型的函数式接口,也就是说,如果 Optional 对象不为空,该方法会直接返回所持有的对象;否则,它会调用 Supplier 函数生成一个默认值并返回。
orElseGet()
方法更加灵活,只有在Optional对象为空时才会执行方法,所有当生成默认对象的成本比较高时,使用该方法更加合适。
Optional<String> optional = getStringOptional();
// 方法一
String str = optional.orElse("other");
// 方法二
String str = optional.orElseGet(() -> "other");
2.4获取Optional的值,如果为空则抛出异常
Optional<String> optional = getStringOptional();
optional.orElseThrow(() -> new RuntimeException("value is empty"));
3.对Optional对象进行进一步链式操作
先定义初始对象
/**
* 获取用户
*/
public class UserResource {
public Optional<User> getUser(String name) {
if ("name".equals(name)) {
return Optional.of(new User("name", 18, "fullName"));
}
return Optional.empty();
}
}
/**
* 用户类
*/
public class User {
String userName;
int age;
String fullName;
public User(String userName, int age, String fullName) {
this.userName = userName;
this.age = age;
this.fullName = fullName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getFullName() {
return fullName;
}
public Optional<String> getFullNameOptional() {
return Optional.ofNullable(fullName);
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
}
使用filert()
方法对Optional对象进行过滤
// 该方法是获取了名称为"name"的对象,如果对象存在则判断age是否大于18
UserResource resource = new UserResource();
Optional<User> userOption = resource.getUser("name")
.filter(user -> user.getAge() > 18);
使用map()
方法和flatMap()
对Optional
// 该方法是获取了名称为"name"的对象,如果对象存在则获取FullName
Optional<String> fullName1 = resource.getUser("name")
.map(User::getFullName);
/*
1、flatMap传入的转换函数返回的必须是一个Optional对象,flatMap会将两个Optional(执行flatMap的Option和转换函数返回的Optional)合并;
2、getFullNameOptional()方法返回的是一个Optional对象,
3、使用Map()方法返回的是一个Optional<Optional<String>>的嵌套对象
4、而使用flatMap()方法则会将Optional的嵌套合并成Optional对象
*/
Optional<String> fullName2 = resource.getUser("name")
.flatMap(User::getFullNameOptional);
Optional<Optional<String>> fullName3 = resource.getUser("name")
.map(User::getFullNameOptional);
不推荐使用Optional的场景
- 不要作为字段类型使用,会增加性能消耗,并且使得序列化的变得复杂;
- 不要作为方法参数使用,Optional的值可能为空会导致方法的执行语义不够清晰,不明确该值是否必须传递,最好通过重载的方式定义为空的情况,更具有可读性;
- 不要用Optional处理集合,集合已经有更好的方式去处理;
- 不推荐使用get()方法,使用get()方法前必须现式的进行判断(这样和显示的判断是否为
null
一一样了),这样无法充分利用Optional的优势。