Java8新特性(三)Optional容器类

一,Optional类的作用

使用Optional类对其他类进行包装,防止空指针,在日常写代码中使用频率不高,在链式编程中使用多一些,个人觉得比较鸡肋。

二,Optional对象的创建

通过如下三个静态方法:

public class TestOptional {
    public static void main(String[] args) {
        //使用of方法创建Optional对象,不能传入null,否则报空指针
        Optional optional1 = Optional.of("aaa");
        System.out.println("Optional.of创建Optional对象:"+optional1.get());

        //使用empty方法创建Optional对象,但调用get方法时会报空指针
        Optional optional2 = Optional.empty();
        //System.out.println("Optional.empty创建Optional对象:"+optional2.get());

        //使用ofNullable方法创建Optional对象,可传入null值,但调用get方法时会报空指针
        Optional optional3 = Optional.ofNullable(null);
        //System.out.println("Optional.ofNullable创建Optional对象:"+optional3.get());
    }
}

运行结果如下:

Java8新特性(三)Optional容器类_第1张图片

由于optional2 和 optional3 的get方法都会报空指针,因此注释掉了。

三,Optional 获取值

有3个方法可以获取值, 有1个方法可以判断是否有值

public class TestOptional {
    public static void main(String[] args) {

        //使用get方法获取值,如果没有值会报空指针
        Optional optional3 = Optional.ofNullable(null);
        //System.out.println("Optional.ofNullable创建Optional对象:"+optional3.get());

        //使用orElse(T t)获取值,有值则返回,无值则返回t
        Optional optional4 = Optional.ofNullable(null);
        System.out.println("Optional.orElse获取值:"+optional4.orElse("bbb"));

        //使用orElseGet(Supplier s)获取值,有值则返回,无值则执行Supplier接口实现类的get方法获取值
        Optional optional5 = Optional.ofNullable(null);
        System.out.println("Optional.orElseGet获取值:"+optional4.orElseGet(()->UUID.randomUUID().toString()));

        //isPresent 是否包含值
        System.out.println("Optional.isPresent()判断Optional中是否有值:"+optional3.isPresent());

    }
}

运行结果如下:

Java8新特性(三)Optional容器类_第2张图片

四,Optional 对值进行处理的方法

提供map和flatMap两个方法对值进行处理:

两个方法入参都是Function接口,只是Function接口返回值不一样(不是map和flatMap的返回值不一样,它俩返回值一样,最终都会被包装成Optional类)

两个方法源码如下:

Java8新特性(三)Optional容器类_第3张图片

Java8新特性(三)Optional容器类_第4张图片

使用示例如下:

public class TestOptional {
    public static void main(String[] args) {
        Optional optional = Optional.ofNullable(new User("A",20,1));

        //使用map方法对Optional中的值进行处理,Function接口的返回值为任意类型
        Optional optional1 = optional.map(User::getName);
        System.out.println("使用map对值进行处理,返回其name:"+optional1.get());

        //使用map方法对Optional中的值进行处理,Function接口的返回值为Optional类型
        Optional optional2 = optional.flatMap((user) -> Optional.ofNullable(user.getName()));
        System.out.println("使用flatMap对值进行处理,返回其name:"+optional2.get());
    }
}

运行结果如下:

Java8新特性(三)Optional容器类_第5张图片

五,使用场景

示例一:stream的reduce方法,其第二种使用方式返回值用到了Optional

public class Test1 {
 
    static List userList = Arrays.asList(
            new User("A",30),
            new User("B",25),
            new User("C",28));
 
    public static void main(String[] args) {
        //reduce的使用,将流中元素按指定规则合并为一个元素
        //reduce第一种用法,传入默认值,那么结果一定不为空,所以返回值类型不是Optional
        Integer reduce1 = userList.stream()
                .map(User::getAge)//只取出年龄放入stream中
                .reduce(0, (x, y) -> x + y);
        System.out.println("对所有user的年龄进行累加,初始值为0,最终累计年龄:"+reduce1);
 
        //reduce第二种用法,不传入默认值,那么结果可能为空,所以返回值类型为Optional
        Optional reduce2 = userList.stream()
                .map(User::getAge)//只取出年龄放入stream中
                .reduce(Integer::sum);//引用Integer.sum方法作为BinaryOperator接口的实现
        System.out.println("对所有user的年龄进行累加,无初始值,最终累计年龄:"+reduce2.get());
    }
}

示例二:在链式编程中使用

使得链能正常走下去,不至于中途发生空指针。

需求:获取Student类中Teacher类的name,如果没有Teacher或者Teacher.name为空都返回"默认老师"

下面分别 不使用Optional 和 使用Optional 进行对比

不使用Optional

public class TestOptional {
    
    public static void main(String[] args) {
        Student student = new Student();
        System.out.println(getTeacherName(student));
    }

    //根据student获取teacher的name
    public static String getTeacherName(Student student){
        //存在大量判空
        if(student!=null){
            Teacher teacher = student.getTeacher();
            if(teacher !=null){
                String name = teacher.getName();
                if(name !=null){
                    return name;
                }
            }
        }
        return "默认老师";
    }
}

class Student{
    private Teacher teacher;
    public Teacher getTeacher() {
        return teacher;
    }
    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }
}

class Teacher{
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

使用Optional进行改写

最大不同在于getTeacherName方法内已经没有null判断了:

public class TestOptional {

    public static void main(String[] args) {
        //使用Optional包装Student,即使student为null也可以
        Optional student = Optional.ofNullable(null);
        System.out.println(getTeacherName(student));
    }

    //根据student获取teacher的name, 入参改为了Optional包装后的Student
    public static String getTeacherName(Optional  student){
        /*
         *最大的变化在这里:
         * 没有null判断了,实现了链式编程
         */
        String name = student.orElse(new Student())//等同于 student==null?new Student():student
                .getTeacher()//得到Optional
                .orElse(new Teacher("默认老师"))//等同于 teacher==null?new Teacher("默认老师"):teacher
                .getName();
        return name;
    }
}

class Student{
    /*
      非常重要:
      使用Optional包装Teacher,且初始化为Optional.empty(),
      因为使用Optional 就是减少空值判断的,如果Optional的变量本身就是null值,则还是要进行null判断就失去了Optional使用的意义
      所以必须给Optional变量初始时就赋非null值
     */
    private Optional teacher = Optional.empty();

    public Optional getTeacher() {
        return teacher;
    }
    public void setTeacher(Optional teacher) {
        this.teacher = teacher;
    }
}

class Teacher{
    private String name;

    public Teacher(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

对比结果:

Optional通过对原始值的包装,通过其orElse方法获取值避免获取到空值,就不必再做null判断了,

但是本人觉得并没有多大改进,判空还是存在,只不过是在orElse方法内部做了null判断。

在实际开发中用null判断更直观快捷,Optional可能在做公共框架或者链式编程中方便一些。

你可能感兴趣的:(java8,java,Java8新特性)