Bootstrap

Java8/9 Optional使用

Java8 引入的 Optional类。主要用来解决空指针异常(NullPointerException),空指针异常是导致Java应用程序失败的最常见原因。

Optional类可以理解为一个容器:它既可以保存类型T的对象,也可以保存null。

Optional类提供了很多有用的方法,并实现了检查空值的功能,程序员就不用显式地写空值检测的代码,再结合函数式编程,使得代码更加干净,简洁。

一、Optional类的使用

在这里插入图片描述

1、创建 Optional实例

Optional类可以理解为一个容器:它既可以保存类型 T的对象,也可以保存 null。

1.1 of方法

of:为非null的值创建一个optional,如果传入为null,则会空指针。

    @Test
    public void testOf(){
        JUser jUser = new JUser();
        jUser.setId(100L);
        jUser.setUsername("赵云");
        jUser.setPazzword("abc123");
        jUser.setHeight(1.78D);
        jUser.setBirthday(new Date());
        jUser.setStatus(JUserStatusEnum.ACTIVATE);

        Optional<JUser> optionalJUser = Optional.of(jUser);
        System.out.println(optionalJUser.get()); // 输出结果:jUser信息

        jUser = null;
        Optional<JUser> optionalJUser2 = Optional.of(jUser);
        System.out.println(optionalJUser2.get()); // 输出结果:java.lang.NullPointerException
    }
1.2 ofNullable方法

ofNullable:为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional。

    @Test
    public void testOfNullable(){
        JUser jUser =  null;
        Optional<JUser> optionalJUser = Optional.ofNullable(jUser);
        System.out.println(optionalJUser); // 输出结果:Optional.empty

        JUser jUser1 = optionalJUser.get();// 输出结果:在这一行报错啦,java.lang.NullPointerException: No value present
    }
1.3 empty方法

empty:返回一个空 Optional实例。

注意: Optional.empty() 所有保存 null包装成的 Optional对象,而且是单例模式的。与泛型无关。

    @Test
    public void testEmpty(){
        Optional<Object> empty = Optional.empty();
        System.out.println(empty); // 输出结果:Optional.empty
        
        Object o1 = Optional.<Integer>empty();
        Object o2 = Optional.<String>empty();
        System.out.println(o1 == o2);// 输出结果:true
    }

2、验证 Optional实例

2.1 isPrensent方法

isPrensent:如果值存在返回true,不存在返回false。

    @Test
    public void testIsPresent(){
        JUser jUser =  null;
        Optional<JUser> optionalJUser = Optional.ofNullable(jUser);
        boolean present = optionalJUser.isPresent();
        System.out.println(present); // 输出结果:false
    }
2.2 ifPresent方法

ifPresent:接受一个Consumer参数,如果对象不为空,就调用consumer接口。否则不做处理。

    @Test
    public void testIfPresent(){
        JUser jUser = new JUser();
        jUser.setId(100L);
        jUser.setUsername("赵云");
        jUser.setPazzword("abc123");
        jUser.setHeight(1.78D);
        Optional<JUser> optionalJUser = Optional.ofNullable(jUser);
        optionalJUser.ifPresent(u -> {
            // 不为 null时才会执行断言
            System.out.println(u);// 输出结果:jUser信息
        });
    }

3、Optional实例使用

3.1 get方法

get:如果有值则返回,没有值抛出 NoSuchElementException异常

    @Test
    public void testGet(){
        JUser jUser =  null;
        Optional<JUser> optionalJUser = Optional.ofNullable(jUser);
//        JUser jUser1 = optionalJUser.get(); // 输出结果:java.lang.NullPointerException

        // 可以使用 isPresent方法检查
        if(optionalJUser.isPresent()){
            System.out.println(optionalJUser.get());// 输出结果:此时为空,不执行该语句
        }
    }
3.2 orElse(方法

orElse(T other):如果保存的值不是null,则返回原来的值,否则返回 other。

    @Test
    public void testOrElse(){
        JUser jUser =  null;
        Optional<JUser> optionalJUser = Optional.ofNullable(jUser);

        JUser jUser1 = optionalJUser.orElse(new JUser());
        System.out.println(jUser1);// 输出结果:jUser实例的默认信息
        // JUser{id=null, username='null', pazzword='null', age=null, age2=0, sex=null, height=null, height2=0.0, birthday=null, status=null}
    }
3.3 orElseGet方法

orElseGet(Supplier<? extends T> other):
如果保存的值不是null,则返回原来的值,否则调用 生产者函数 并返回调用结果的。

    @Test
    public void testOrElseGet(){
        JUser jUser =  null;
        Optional<JUser> optionalJUser = Optional.ofNullable(jUser);

        JUser jUser1 = optionalJUser.orElseGet(() -> {
            JUser u = new JUser();
            u.setId(100L);
            u.setUsername("赵云");
            return u;
        });
        System.out.println(jUser1);// 输出结果:u实例信息
        // JUser{id=100, username='赵云', pazzword='null', age=null, age2=0, sex=null, height=null, height2=0.0, birthday=null, status=null}
    }

注意:orElse和 orElseGet方法的区别

  • 如果 Optional保存的是 null值时,两者调用方法的效果一样的。但是,orElse可以返回任何类型 T的值,而 orElseGet必须是 Supplier函数返回的调用结果。
  • 如果 Optional保存的不是 null值时,两者调用方法的效果一样的。
3.4 orElseThrow方法

orElseThrow(Supplier<? extends X> exceptionSupplier):有值返回,没有值抛出 supplier接口创建的异常

    @Test
    public void testOrElseThrow(){
        JUser jUser =  null;
        Optional<JUser> optionalJUser = Optional.ofNullable(jUser);

        JUser jUser1 = optionalJUser.orElseThrow(() -> {
            return new RuntimeException("testOrElseThrow ");
        });
        // 输出结果:java.lang.RuntimeException: testOrElseThrow 
    }
3.5 map方法

map(Function<? super T,? extends U> mapper):
有值,就调用 Function函数并返回生成的值。否则返回空的Optional。

    @Test
    public void testMap(){
        JUser jUser =  new JUser();
        jUser.setId(100L);
        jUser.setUsername("赵云");
        Optional<JUser> optionalJUser = Optional.ofNullable(jUser);

        Optional<JUser> optionalJUser1 = optionalJUser.map((u) -> {
            u.setId(u.getId() + 100L);
            u.setUsername("赵云2");
            return u;
        });
        System.out.println(optionalJUser1.get());// 输出结果:JUser{id=200, username='赵云2', pazzword='null', age=null, age2=0, sex=null, height=null, height2=0.0, birthday=null, status=null}
        // 如果 jUser= null,则输出结果:java.lang.NullPointerException
    }
3.6 flatMap方法

flatMap(Function<? super T, ? extends Optional<? extends U>> mapper):
它map类似,区别在于他调用结束的时候,不会对Optional做一个封装

    @Test
    public void testFlatMap() {
        JUser jUser = new JUser();
        jUser.setId(100L);
        jUser.setUsername("赵云");
        Optional<JUser> optionalJUser = Optional.ofNullable(jUser);

        Optional<JUser> optionalJUser1 = optionalJUser.flatMap((u) -> {
            //需要我们自己的去封装一个Optional
            u.setId(u.getId() + 100L);
            u.setUsername("赵云2");
            return Optional.of(u);
        });
        System.out.println(optionalJUser1.get());// 输出结果:JUser{id=200, username='赵云2', pazzword='null', age=null, age2=0, sex=null, height=null, height2=0.0, birthday=null, status=null}
        // 如果 jUser= null,则输出结果:java.lang.NullPointerException
    }
3.7 filter方法

filter:有值,返回满足条件的Optional。否则返回空的Optional

    @Test
    public void testFilter() {
        JUser jUser = new JUser();
        jUser.setId(100L);
        jUser.setUsername("赵云");
        Optional<JUser> optionalJUser = Optional.ofNullable(jUser);

        // 没有满足的,返回空的Optional
        Optional<JUser> optionalJUser1 = optionalJUser.filter(u -> {
            return u.getId() == 1;
        });
        System.out.println(optionalJUser1.get());// 输出结果:java.util.NoSuchElementException: No value present
    }

4、Optional类的链式方法

在这里插入图片描述

二、JDK9的增强

上面介绍了 Java 8 的特性,Java 9 为 Optional 类添加了三个方法:

  • or()
  • ifPresentOrElse()
  • stream()。

1、or方法

or() 方法与 orElse() 和 orElseGet() 类似,它们都在对象为空的时候提供了替代情况。

or() 的返回值是由 Supplier 参数产生的另一个 Optional 对象。

    @Test
    public void testOr() {
        JUser jUser = null;
        Optional<JUser> optionalJUser = Optional.ofNullable(jUser);

        Optional<JUser> optionalJUser1 = optionalJUser.or(() -> {
            JUser u = new JUser();
            u.setId(100L);
            u.setUsername("赵云");
            return Optional.of(u);
        });
        System.out.println(optionalJUser1.get());// 输出结果:u信息
    }

2、ifPresentOrElse方法

ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction):
如果对象包含值,会执行 Consumer 的动作,否则运行 Runnable。

    @Test
    public void testIfPresentOrElse() {
        JUser jUser = null;
        Optional<JUser> optionalJUser = Optional.ofNullable(jUser);

        optionalJUser.ifPresentOrElse(u -> System.out.printf("user id = {}" + u.getId()),
                        () -> System.out.printf("User not found"));
        // 输出结果:User not found
    }

3、stream方法

stream() 方法,它通过把实例转换为 Stream对象,让你从广大的 Stream API中受益。如果没有值,它会得到空的 Stream;有值的情况下,Stream则会包含单一值。

    @Test
    public void testStream() {
        JUser jUser = new JUser();
        jUser.setId(100L);
        jUser.setUsername("赵云");
        List<JUser> jUserList = Optional.ofNullable(jUser)
                .stream()
                .filter(u -> u.getId() == 100)
                .map(u -> {
                    u.setId(u.getId() + 100L);
                    u.setUsername("赵云2");
                    return u;
                })
                .collect(Collectors.toList());
        System.out.println(jUserList);// 输出结果:数据
    }

在这里插入图片描述

总结:
Optional 是 Java 语言的有益补充 —— 它旨在减少代码中的 NullPointerExceptions,虽然还不能完全消除这些异常。它也是精心设计,自然融入 Java 8 函数式支持的功能。
总的来说,这个简单而强大的类有助于创建简单、可读性更强、比对应程序错误更少的程序。

参考文章:

– 求知若饥,虚心若愚。

;