Optional类
Optional类 为java 1.8 以后添加的解决空指针的类。介绍不多说,下面我们先准备一下数据:
建立一个student类
再建一个Detail 类 。
数据结构如下:
@Data
@NoArgsConstructor
public class Student {
private Integer id;
private String name;
private Integer age;
private List<String> listStrings;
private Detail detail;
private Optional<Detail> optionalDetail;
public Student(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student" + JSON.toJSONString(this);
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Detail {
private Integer id;
private String country;
private String city;
}
- 如果我们要得到student中的detail对象中的country信息 ,传统为了避免空指针我们需要这样写
String country = null;
if(null != student){
Detail detail = student.getDetail();
if(null != detail){
country = detail.getCountry();
}
}
如果这个detail中再嵌套其他类呢?再接着嵌套呢,我们是不是要疯掉。
String country = student.getDetail().getCountry().xxxx().xxxx().xxxx();
拓展一个小知识: |
---|
如果country为空 。我们这样的一个调用,不去处理NullPointerException 如果中间有一个数据报错,就会造成无法一次性定为空指针出现在哪个地方。Exception in thread “main” java.lang.NullPointerExceptionat NullPointerExample.main(NullPointerExample.java:1)在Java 14中,新的JVM特性可以显示更详细的诊断信息:Exception in thread “main” java.lang.NullPointerException: Cannot invoke “xxxx()” because the return value of “Detail.getCountry()” is nullat NullPointerExample.main(NullPointerExample.java:1)**增强版本的诊断信息只有在使用下述标志运行Java时才有效:XX:+ShowCodeDetailsInExceptionMessages下面是个例子:java -XX:+ShowCodeDetailsInExceptionMessages NullPointerExample |
Optional中 of(T)和ofNullable(T)区别
- 如果Student类是我们从数据库中查出来的,我们不知道数据存不存在,返回的数据是否为空,我们就可以用
java Optional<Student> stuOfNullOptional = Optional.ofNullable(student);
处理这个类。 - 如果 Student这个类是接收的,我们暂时不知道里面参数赋值了哪些可以用
Optional<Student> stuOfOptional = Optional.of(student);
处理。
Optional.of(T) 如果传了一个空值,他会包空指针错误,具体可参考源码:、
// of 返回了一个new Optional<>(value);
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
//Optional(T value)调用了 Objects.requireNonNull(value)
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
//如果为空 抛出空指针异常
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
ofNullable(T) 方法不会抛出空指针 源码如下:
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
//如果为空 调用empty() 方法 返回EMPTY
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
//EMPTY 是 new Optional<>()
private static final Optional<?> EMPTY = new Optional<>();
private Optional() {
this.value = null;
}
Optional中 get() 方法
Optional< T >中的 get() 方法就是得到泛型的数据。 源码为:
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
通过介绍可知:Optional< Student> stuOfNullOptional = Optional.ofNullable(null);->
Optional 如果调用 get() 依然会报错。
得到country 的值, 当 Detail 为空时,或者 country 为空时返回默认值 中国 。
我们可以 这样写:
String detailCountry = stuOfNullOptional.map(Student::getDetail)
.map(Detail::getCountry).orElseGet(() -> "中国");
//返回结果为
这样我们就介意避免多层 if 判断。
map 和 flatMap 使用
map和flatMap功能大致相似区别源码中有体现 源码如下:
//接收的参数为 普通类
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
//接收的参数为 Optional<T> 类
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}
我们这次从student 类中拿 optionalDetail 对象中 country的值如果有就返回,没有就抛出错误异常 操作为:
String flatCountry = stuOfNullOptional.flatMap(Student::getOptionalDetail)
.map(Detail::getCountry).orElseThrow(() -> new RuntimeException("错误"));
System.out.println(flatCountry);
测试发现 ,并没有打印 错误异常
相信聪明的你一定知道答案。
我们只需在student中加上
Detail detail = new Detail();
student.setOptionalDetail(Optional.of(detail));
上面的代码运行结果就成为我们想要的结果了。
结果如下:
orElse() 、 orElseGet()和 filter() 方法
orElse 和 orElseGet 方法这里就不再做测试了,其他博客写的也很详细。
- orElse 是不管前面判断是否为真,orElse 中结果都会执行。
- orElseGet 只有当结果为假的时候,才执行orElseGet中的方法。
- filter方法就是常规的过滤器这里也不再介绍,集合操作中运用颇多。
标题 ifPresent()方法
Optional 中 ifPresent 方法有两个,一个是空餐构造方法,返回值为boolen 类型,一个为有参方法,返回值为空。
- isPresent 空餐方法就是一个简单的非空判断
- ifPresent有参方法可以做一些排序和添加数据使用
- 例如:我想让student 中listStrings 如果不为空 按照自然数排序。
//结果为:[2, 3, 7, 9]
List<String> lists = new ArrayList<>(Arrays.asList("2","9","3","7"));
student.setListStrings(lists);
Optional.ofNullable(student.getListStrings())
.ifPresent(list -> list.sort(Comparator.naturalOrder()));
System.out.println(student.getListStrings());
- student 中listStrings 如果不为空,我们添加一个“888“ 在list中。
//结果为 [2, 3, 7, 9, 888]
Optional.ofNullable(student.getListStrings())
.ifPresent(list -> list.add("888"));
System.out.println(student.getListStrings());
结尾
Optional 类中还有toString()、hashCode()、equals方法没有介绍,这些大家已经很熟悉了这里就不再赘述。
如本文有不正确的地方还需大家批评指正。
源码很重要,学习也很重要 。与君共勉!