Optional在jdk8中引入,已经有很长时间了,但是对于它的使用在平时的项目中最多只是拿它做下面这样的处理:
XX e = Optional.ofNullable(xx.xx(x.x()))
.orElseThrow(() -> new xxException("xxx"));
判断某个方法返回的值是否为null,如果是会抛出一个异常。
在Optional引入之前处理null都是使用if去判断,这样写起来有点繁琐,但是最主要的还是很容易忘记判断值是否为null。使用可能为null的值去执行程序会出现很多意想不到的结果,可能会抛出NPE,可能出现一些其他的问题。为了避免这些问题所以jdk8引入了Optional去处理,当然上面的例子只是很简单的使用,也可以说不是很正确的使用。
在哪用
-
在可能为空的成员变量的get方法上使用Optional返回
class Student {
//name可能为null
private String name;
//id肯定不会为null
private Integer id;
public Student(String name) {
this.name = name;
}
public Optional<String> getName() {
return Optional.of(name);
}
public Integer getId(){
return id;
}
}
-
不要在set方法和构造方法参数上使用Optional接收参数
在set方法和构造函数上如果使用Optional接收参数会使调用这个方法的人很痛苦,因为它需要包装成Optional然后去调用。最好的做法应该是便利胜过对输入的严格要求。
-
使用Optional作为业务逻辑方法的返回结果
public Optional<Address> getAdderss(){
//做一些逻辑处理
return ...//如果找到了地址则返回对应的地址的Optional,如果没有找到则返回Optional.empty()
}
看本文开头的例子,就是一种不好的返回方式,应该返回一个被Optional包装的值,而不是直接返回真实的值。
如何用
拿到了对应的Optional如何来做处理?
optionalStudent.get().getName();
上面的这种方式直接去使用get去获取Optional中的值是有问题,因为当Optional中包装的值是null,还是会抛出异常。
下面换一种方式确保它不为空再使用。
if(optionalStudent.isPresent()){
optionalStudent.get().getName();
}
上面的那种方式和以前的写法没有什么区别,没有将Optional的功能用好。也同样存在忘记判断是否为null后再去使用。
Optional<Student> optionalStudent = Optional.ofNullable(new Student(null));
System.out.println(optionalStudent.map(Student::getName).orElse("xx"));
System.out.println(optionalStudent.map(Student::getName).orElseThrow(() -> new Exception()));
class Student {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
可以使用上面的方式获取,如果在值为Student的name为null的情况下,或返回一个指定的字符串“xx”。当然也可以抛出异常。
上面的例子是一个对象里的成员变量是null,如果返回的对象就是null呢,上面的程序还是会一样的执行吗,比如:
//这里给定的是null
Optional<Student> optionalStudent = Optional.ofNullable(null);
System.out.println(optionalStudent.map(Student::getName).orElse("xx"));
System.out.println(optionalStudent.map(Student::getName).orElseThrow(() -> new Exception()));
这里还是会和上面执行的结果一样。当然也可以使用ifPresent方法,当值不为null时才会执行里面的代码。
optionalStudent.ifPresent(student -> {
//不为null时才会执行
System.out.println(student.getName());
});
参考资料
https://blog.joda.org/2015/08/java-se-8-optional-pragmatic-approach.html