java8 Optional类的简单使用

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有参方法可以做一些排序和添加数据使用
  1. 例如:我想让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());
  1. 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方法没有介绍,这些大家已经很熟悉了这里就不再赘述。
如本文有不正确的地方还需大家批评指正。
源码很重要,学习也很重要 。与君共勉!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值