Java-Optional学习笔记

    科技2022-07-15  123

    Java-Optional学习笔记

    文章目录

    Java-Optional学习笔记1.创建Optional对象2.获取封装值的方法3.当封装值为null时的解决方法3.1get()的替代方案3.2对值进行处理 4.实战演练5.总结

      Optional<T>是一个容器类,它的提出是为了尽量减少空指针异常,其基本理念是将那些可能为空的对象封装成为Optional。当对Optional封装好的对象进行操作时,为了避免对象空指针异常,Optional提供了一系列的解决方案。具体的阐述见文末的测试案例。

    1.创建Optional对象

      Optional的构造函数是私有的,因此Optional提供了三种静态方法进行对象创建。

    1.Optional<T> : Optional.of(T t) 返回一个封装值为t的Optional实例。要求t不能为null,否则报空指针异常

    2.Optional<T> : Optional.empty()返回一个封装值为null的Optional实例。

    3.Optional<T> : Optional.ofNullable(T t)返回一个封装值为t的Optional实例。其底层实际是对t进行判断,根据是否为null,分别调用1或是2创建实例。

    public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); }

    Demo

    情景描述:

    产生一个要么是0要么是1的随机数,如果是0就创建封装值为null的实例,否则就创建封装值是1的实例

    代码

    @Test public void testCreateOptional(){ Optional<Integer> x; if(new Random().nextInt(2)==1){ //创建一个封装的值为 1 的Optional实例 //特别地,当of传入的值为null时,会报空指针异常 x = Optional.of(1); }else { //创建一个封装值为null 的Optional的实例 x = Optional.empty(); } // 另一种方案: Optional<Integer> y=Optional.ofNullable(get1OrNull()); } public static Integer get1OrNull(){ return new Random().nextInt(2)==1?1:null; }

    2.获取封装值的方法

      T get() ,不过需要注意的是,当封装值为null时,采用此方法将会造成空指针异常。

    3.当封装值为null时的解决方法

      没有采用Optional之前,如果我们调用一个不知道是否为null的对象的属性或是方法时,需要对该对象进行判断,判断的结构如下:

    if(x!=null) x.method;

     采用Optional之后,方案将会有所不同,下面将根据直接获得值get()或是对值进行处理两种方式进行阐述:

    3.1get()的替代方案

      Optional提供了一些方法来对封装值为null进行处理:

    T orElse(T other),当封装值不为null时,此方法等价于get()方法,当封装值为null时,返回otherT orElseGet(Supplier<? extends T> other),当封装值不为null时,此方法等价于get()方法,当封装值为null时,返回other.get()<X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier),当封装值不为null时,此方法等价于get()方法,当封装值为null时,将抛出exceptionSupplierr.get()代表的异常。

    测试代码:

    @Test public void testHandleOptional(){ Optional<Integer> x = Optional.ofNullable(get1OrNull()); //替代值-1 Integer ans1 = x.orElse(-1); System.out.println(ans1); //使用Supplier替代值 (产生 0 或是 -1) Integer ans2= x.orElseGet(()->((int) (Math.random() * 2)-1)); System.out.println(ans2); //抛出异常 Integer ans3=x.orElseThrow(NullPointerException::new); System.out.println(ans3); } public static Integer get1OrNull(){ return new Random().nextInt(2)==1?1:null; }

    3.2对值进行处理

      下面展示两种方式,一种方式是对值进行处理,但是不返回值,另一种方式是对值进行处理并返回值

    方式1

    void ifPresent(Consumer<? super T> consumer)

    如果Optional的封装值不为null,则对其进行consumer.accept(t)处理

    方式2

    <U> Optional<U> map(Function<? super T, ? extends U> mapper); //或 //要求mapper.apply(t)返回的值不能为null,否则空指针异常 <U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)

    map 的机理是对Optional的封装值进行映射以后,再对映射后的值封装为一个Optional。

    flatMap的机理是直接把Optional的封装值映射为Optional然后返回,不过必须要求Optional本身不为null。

    特别地,如果Optional封装的值为null,那么两个方法返回的Optional的封装的值也为null

    测试代码:

    @Test public void testHandleOptional(){ Optional<Integer> x = Optional.ofNullable(get1OrNull()); //对x的封装值进行处理但是不返回值 x.ifPresent(System.out::println); Optional<Integer> a = Optional.of(1); Optional<String> res1 = a.map(ele -> ele.getClass().getSimpleName() + ":" + ele); // Optional<String> res2 = a.flatMap(ele -> Optional.of(ele.getClass().getSimpleName() + ":" + ele)); // 空指针异常 a.flatMap(ele ->null); }

    4.实战演练

    情景描述

    封装一个User类,假定其email属性可能为null。

    创建一个测试类,获取一个User对象的email属性,并打印输出。

    分析

    email的属性可能为null,这说明对email的操作可能出现空指针异常,那么需要Optional对其进行封装。

    代码如下:

    User

    package com.lordbao.entity; import com.sun.istack.internal.NotNull; import java.util.Optional; /** * @Author Lord_Bao * @Date 2020/10/4 15:23 * @Version 1.0 */ public class User { private String username=""; //不能为private Optional<String> email ; //这样仍然可能出现空指针异常。 private Optional<String> email = Optional.empty(); public User() { } public User(String username, Optional<String> email) { this.username = username; this.email = email; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Optional<String> getEmail() { return email; } public void setEmail(Optional<String> email) { this.email = email; } @Override public String toString() { return "User{" + "username='" + username + '\'' + ", email=" + email + '}'; } }

      其中有一行代码private Optional<String> email = Optional.empty();需要注意,我们要求Optional的封装值可为null,但是Optional本身不能为null,否则就没有发挥Optional的作用。

    测试代码

    @Test public void test(){ User user1 = new User(); String email1 = user1.getEmail().orElse("BOSS@126.com"); System.out.println(email1); User user2 = new User("jack",Optional.of("jack@126.com")); String email2 = user2.getEmail().orElse("BOSS@126.com"); System.out.println(email2); }

    打印结果

    BOSS@126.com jack@126.com

    5.总结

      Optional的提出是为了尽可能减少空指针,它的解决思想其实就是底层提供方法对那些可能是null的引用对象进行处理。比如空指针的替代方法 orElse orElseGet等等。

    Processed: 0.013, SQL: 8