学习Java8中Optional

一、Java8之前访问对象的属性或方法

Java8之前访问对象的属性或方法,会使用到以下方式,以下方式可能会造成空指针异常

String code = user.getAddress().getCountry().getCode().toUpperCase();

在上面的代码中,如果要确保不发生空指针异常必须使用非空判断,如下所示

if (null!=user) {
    Address address = user.getAddress();
    if (null!=address ) {
        Country country = address.getCountry();
        if (null!=country ) {
            String code = country.getCode();
            if (null!=code) {
                code = code.toUpperCase();
            }
        }
    }
}

代码变得很冗长,难以维护。并且如果再新增加属性,将会增加更多的if判断。为了简化这个过程,我们来看看用 Optional  类是怎么做的。从创建和验证实例,到使用其不同的方法,并与其它返回相同类型的方法相结合,下面是见证 Optional  奇迹的时刻。

二、创建Optional对象

1. 创建包含空值的Optional

Optional.empty();

Optional.of()/Optional.ofNullable()

你可以使用Optional.of()或ofNullable()方法创建Optional对象,两个方法的区别是,使用Optional.of()方法创建对象时,当参数为null时,调用get()方法,程序会抛出NullPointerException。如下图所示

学习Java8中Optional

使用Optional.ofNullable(),当参数为null时,程序会抛出java.util.NoSuchElementException: No value present 异常。如下图所示

学习Java8中Optional

三、获取Optional对象的值

1. get()方法

使用get()方法,此方法在值为null时,抛出异常

  @Test
    public void getOptionValue(){
            String name = "John";
        Optional<String> opt = Optional.ofNullable(name);
        System.out.println(opt.get());

    }

2. isPresent()

判断是否有值,再进行后续操作

@Test
    public void getOptionValue(){
            String name = "John";
        Optional<String> opt = Optional.ofNullable(name);
        if(opt.isPresent()){
            System.out.println(opt.get());
        }
    }

3. ifPresent()

判断是否有值再进行后续操作,接受一个Consumer(消费者) 参数,如果对象不是空的,就对执行传入的 Lambda 表达式

    @Test
    public void getOptionValue(){
            String name = "John";
        Optional<String> opt = Optional.ofNullable(name);
        opt.ifPresent(System.out::println );
    }

四、返回默认值

1. orElse()

orElse()方法,它的工作方式非常直接,如果有值则返回该值,否则返回传递给它的参数值。如下示例代码,如果name为null则返回"Sim",如果name不为空则直接返回name。

 @Test
    public void getOptionOrElse(){
        String name = null;
        Optional<String> opt = Optional.ofNullable(name);
        String nameStr= opt.orElse("Sim");
        System.out.println(nameStr);
    }

2.orElseGet()

此方法略有不同。这个方法会在有值的时候返回值,如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果:

 @Test
    public void getOptionOrElseGet(){
        User user =null;
        User user2 = new User();
        user2.setName("abc");
        User user3=  Optional.ofNullable(user).orElseGet(
                () -> user2);
        System.out.println(user3);
    }

3.orElse和orElseGet区别

当Optional中对象为空是,两者没有区别都,返回默认值或供给函数提供的值。

当Optional中对象不为空,orElse仍然执行产生默认值的方法,如下图所示:

学习Java8中Optional

当Optional中对象不为空,orElseGet不会执行产生默认值的方法,如下图所示:

学习Java8中Optional

五、返回异常

1.orElseThrow()

当Optional对象值为空的时抛出异常,异常可以自定义。

@Test
    public void getOptionOrElseThrow(){
        User user2 = null;
        //当user2为空时,抛出异常
        User user3=  Optional.ofNullable(user2).orElseThrow(
                () -> new IllegalArgumentException() );
    }

六、转换值

1.map方法

map方法接收一个function接口,并且把返回值包装成Optional对象,使对返回值进行链式调用的操作成为可能,如下代码所示,调用map后,可紧着调用orElse

   @Test
    public void testMap(){
        User user2 = new User();
        user2.setName("Lisa");
        user2.setAddress("上海");

        String address =
                Optional.ofNullable(user2).
            map(u -> u.getAddress()).orElse("北京");
        System.out.println(address);
    }

2.flatMap

map方法接收一个function接口,返回值直接是一个Optional对象,不需要进行重新包装。

public Optional<String> getCode(){
        return Optional.ofNullable(code);
    } 

@Test
    public void testFlatMap(){
        User user2 = new User();
        user2.setName("Lisa");
        user2.setAddress("上海");
        String code =
                Optional.ofNullable(user2).flatMap(u -> u.getCode()).orElse("北京");
        System.out.println(code);
    }

七、过滤值

Optional  类也提供了按条件“过滤”值的方法,filter() 接受一个 Predicate 参数,返回测试结果为 true 的值。如果测试结果为 false,会返回一个空的 Optional。

  @Test
    public void testFilter() {
        User user = new User();
        user.setEmail("anna@gmail.com");
        Optional<User> result =
                Optional.ofNullable(user)
                .filter(u -> StringUtils.isNotEmpty(u.getEmail()) && u.getEmail().contains("@"));
        System.out.println(result);
    }

八、怎么使用Optional

1.使用场景

Optional 主要用作返回类型。在获取到这个类型的实例后,如果它有值,你可以取得这个值,否则可以进行一些替代行为。

Optional 类有一个非常有用的用例,就是将其与流或其它返回 Optional 的方法结合,以构建流畅的API。

2.不适合使用场景

Optional 不是 Serializable。因此,它不应该用作类的字段。如果你需要序列化的对象包含 Optional 值,Jackson 库支持把 Optional 当作普通对象。也就是说,Jackson 会把空对象看作 null,而有值的对象则把其值看作对应域的值。这个功能在 jackson-modules-java8 项目中。

它在另一种情况下也并不怎么有用,就是在将其类型用作方法或构建方法的参数时,这样做会让代码变得复杂,完全没有必要。比如以下代码

User user = new User(23, "Lisa", Optional.empty());

九、总结

Optional主要用来解决空指针异常,结合Stream流及Lambda表达式,使应用程序更加优化及健壮。


上一篇:微软 Word 曝零日攻击漏洞 涉及所有版本


下一篇:Ubuntu 快速更换阿里源