写点什么

Optional 的使用详解

作者:echoes
  • 2022 年 7 月 14 日
  • 本文字数:8432 字

    阅读完需:约 28 分钟

Optional的使用详解

一、Optional 介绍

Optional 被定义为一个简单的容器,它可以保存类型 T 的值,其值可能是 null 或者不是 null。在 Java 8 之前一般某个函数应该返回非空对象但是偶尔却可能返回了 null,而在 Java 8 以后,不推荐你返回 null 而是返回 Optional。

二、Optional 用法

从方法作用来划分,主要可以分为:构建类方法,获取类方法,判断类方法,过滤类方法,映射类方法

1.构建类方法


  • Optional.of(T t) : 创建一个 Optional 实例,t 必须非空;

  • Optional.empty() : 创建一个空的 Optional 实例

  • Optional.ofNullable(T t):t 可以为 null

2.获取类方法

  • T get(): 如果调用对象包含值不为 null,返回该值,否则抛异常

  • T orElse(T other) :如果有值则将其返回,否则返回指定的 other 对象。

  • T orElseGet(Supplier<? extends T> other) :如果有值则将其返回,否则返回由 Supplier 接口实现提供的对象。

  • T orElseThrow(Supplier<? extends X> exceptionSupplier) :如果有值则将其返回,否则抛出由 Supplier

3.判断类方法

  • boolean isPresent() : 判断是否包含对象

  • void ifPresent(Consumer<? super T> consumer) :如果有值,就执行 Consumer 接口的实现代码,并且该值会作为参数传给它。

  • void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) :如果有值,就执行 Consumer 接口的实现代码,并且该值会作为参数传给它,否则执行 Runnable 接口的实现代码。

4.过滤类方法


  • Optional<T> filter(Predicate<? super <T> predicate):如果值存在,并且这个值匹配给定的 predicate,返回一个 Optional 用以描述这个值,否则返回一个空的 Optional。

5.映射类方法

<U>Optional<U> map(Function<? super T,? extends U> mapper):如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的 Optional 作为 map 方法返回值,否则返回空 Optional。

<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper):如果值存在,就对该值执行提供的 mapping 函数调用,返回一个 Optional 类型的值,否则就返回一个空的 Optional 对象


三、源码解析及示例

Optional 代码结构

示例代码

@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic class Trade {
String iName; String iCode; String iType;
}
复制代码

1、创建 Optional 对象

1.Optional.of(T t)

/** * 有参构造   使用描述的值构造一个实例。   参数:值–要描述的非null值   抛出:NullPointerException如果值为null */private Optional(T value) {    this.value = Objects.requireNonNull(value);}//Objects.javapublic static <T> T requireNonNull(T obj) {    if (obj == null)        throw new NullPointerException();    return obj;}
/** 返回一个Optional描述给定的非null值。 参数:value 要描述的值,必须为非null 类型参数:<T> –值的类型 返回值:存在值的Optional,若为null则抛出NullPointerException异常 */ public static <T> Optional<T> of(T value) { return new Optional<> (value); }
复制代码

示例

  public void ofTest1(){        Trade trade = Trade.builder ()                .iCode ("qyz0711")                .iName ("青衣醉0711")                .iType ("0711")                .build ();        Optional<Trade> optionalTrade = Optional.of (trade);    }
复制代码

2.Optional.empty()

private static final Optional<?> EMPTY = new Optional<>();
private Optional() { this.value = null; }/** 返回一个空的Optional实例。 此Optional没有值。 类型参数:<T> 不存在的值的类型 返回值:一个空的Optional api注意: 尽管这样做可能很诱人,但应通过将==与Optional.empty()返回的实例进行比较来避免测试对象是否为空。 不能保证它是一个单例。 而是使用isPresent() */ public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }
复制代码

3.Optional.ofNullable(T value)

/**        返回一个描述给定值的Optional ,如果为null ,则返回一个空的Optional,否则返回给定值的Optional 。        参数:值描述的可能为null值        类型参数:<T> –值的类型        返回值:一个Optional与如果指定值是非当前值null ,否则一个空Optional     */public static <T> java.util.Optional<T> ofNullable(T value) {    return value == null ? empty() : of(value);}
复制代码

4.示例测试

 				// 构建一个value不可以为null的optional对象,如果of()的入参为null会报空指针异常;        Optional<Trade> of1 = Optional.of (trade);        System.out.println ("of1:"+of1);
//返回一个描述给定值的Optional ,如果为null ,则返回一个空的Optional,否则返回给定值的Optional 。 Optional<Trade> ofNullable1 = Optional.ofNullable (trade); Optional<Trade> ofNullable2 = Optional.ofNullable (null); System.out.println ("ofNullable1:"+ofNullable1); System.out.println ("ofNullable2:"+ofNullable2);
结果:of1:Optional[Trade(iName=青衣醉0711, iCode=qyz0711, iType=0711)]ofNullable1:Optional[Trade(iName=青衣醉0711, iCode=qyz0711, iType=0711)]ofNullable2:Optional.empty
复制代码


2、获取类方法

1.Optional.get()

/**  			如果存在值,则返回该值,否则抛出NoSuchElementException 。        返回值:此Optional描述的非null值        抛出:NoSuchElementException如果不存在任何值        api注意:此方法的首选替代方法是orElseThrow() */public T get() {    if (value == null) {        throw new NoSuchElementException("No value present");    }    return value;}
复制代码

2.Optional.orElse(T other)

/**
如果存在值,则返回该值,否则返回other 。
参数:其他–要返回的值(如果不存在任何值)。 可以为null 。 返回值:值(如果存在),否则other*/public T orElse(T other) { return value != null ? value : other;}
复制代码

3.Optional.orElseGet(Supplier<? extends T> other)

/**
如果存在值,则返回该值,否则返回由供应函数supplier产生的结果。 返回值:如果不存在值,且supplier为null,则抛出NullPointerException*/public T orElseGet(Supplier<? extends T> supplier) { return value != null ? value : supplier.get();}
复制代码

4.Optional.orElseThrow(Supplier<? extends X> exceptionSupplier)

/** 与get 方法相同*/public T orElseThrow() {    if (value == null) {        throw new NoSuchElementException("No value present");    }    return value;}/**如果存在值,则返回该值,否则抛出由异常提供函数产生的异常。				类型参数:<X> –引发的异常类型        返回值:值(如果存在)        抛出:X –如果不存在任何值NullPointerException如果不存在任何值并且异常提供函数为null        api注意:带有空参数列表的对异常构造函数的方法引用可用作提供者*/public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {        if (value != null) {            return value;        } else {            throw exceptionSupplier.get();        }    }
复制代码


5.or(Supplier<? extends Optional<? extends T>> supplier)

/**如果值存在时,返回一个Optional描述的值,否则将返回一个Optional产生通过供给功能。   参数:供应商–产生要返回的Optional的供应功能    返回值:返回一个Optional描述此的值Optional ,如果一个值存在,否则Optional所生产的供应功能。    抛出:NullPointerException如果提供的函数为null或产生null结果 * @since 9 */public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {    Objects.requireNonNull(supplier);    if (isPresent()) {        return this;    } else {        @SuppressWarnings("unchecked")        Optional<T> r = (Optional<T>) supplier.get();        return Objects.requireNonNull(r);    }}
复制代码


6.示例代码

@Test    public void getTest02(){        Trade trade = Trade.builder ()                .iCode ("qyz0711")                .iName ("青衣醉0711")                .iType ("0711")                .build ();        Trade defaultTrade = Trade.builder ()                .iCode ("MR1016")                .iName ("默认值")                .iType ("1016")                .build ();        Optional<Trade> tradeInfoEmptyOpt = Optional.empty();        Optional<Trade> tradeInfoOpt = Optional.of(trade);        // 1、get()-> 直接获取,注意如果value==null,会报NoSuchElementException异常        Trade trade1 = tradeInfoOpt.get();        System.out.println ("1、get():"+trade1);
//2、orElse(T other)-> orElse可以传入一个Trade类型的参数当默认值,若value==null,则返回会默认值,否则返回value Trade trade2 = tradeInfoEmptyOpt.orElse (defaultTrade); Trade trade3 = tradeInfoOpt.orElse (defaultTrade); System.out.println ("2、orElse(),value == null:"+trade2); System.out.println ("2、orElse(),value != null:"+trade3);
//3、orElseGet(Supplier<? extends T> other)-> 如果存在值,则返回该值,否则返回由供应函数supplier产生的结果。 // 如果不存在值,且supplier为null,则抛出NullPointerException,和orElse不同的是orElseGet可以传入一段lambda表达式; Trade trade4 = tradeInfoEmptyOpt.orElseGet (() -> defaultTrade); Trade trade5 = tradeInfoOpt.orElseGet (() -> defaultTrade); //Trade trade6 = tradeInfoEmptyOpt.orElseGet (null);不存在值,且supplier为null,则抛出NullPointerException System.out.println ("3、orElseGet(other),value == null:"+trade4); System.out.println ("3、orElseGet(other),value != null:"+trade5);
//4、orElseThrow(Supplier<? extends X> exceptionSupplier)-> 可以传入一段lambda表达式, // lambda返回一个Exception;当value!=null时,返回value值;当value==null时,抛出该异常;。 Trade trade7 = tradeInfoOpt.orElseThrow (NullPointerException::new); System.out.println ("4、orElseThrow(exceptionSupplier),value == null:"+trade7); //5、or(Supplier<? extends Optional<? extends T>> supplier)->如果值存在时,返回一个Optional描述的值,否则将返回一个Optional产生通过供给功能。 Optional<Trade> optTrade = tradeInfoEmptyOpt.or(()->{ return Optional.of (Trade.builder () .iCode ("OR0714") .iName ("OR0714") .iType ("0714") .build ()); }); if (optTrade.isPresent ()) { System.out.println ("5.or(supplier)"+optTrade.get ()); } }

结果:1、get():Trade(iName=青衣醉0711, iCode=qyz0711, iType=0711)2、orElse(),value == null:Trade(iName=默认值, iCode=MR1016, iType=1016)2、orElse(),value != null:Trade(iName=青衣醉0711, iCode=qyz0711, iType=0711)3、orElseGet(other),value == null:Trade(iName=默认值, iCode=MR1016, iType=1016)3、orElseGet(other),value != null:Trade(iName=青衣醉0711, iCode=qyz0711, iType=0711)4、orElseThrow(exceptionSupplier),value == null:Trade(iName=青衣醉0711, iCode=qyz0711, iType=0711)5、or(supplier)Trade(iName=OR0714, iCode=OR0714, iType=0714)
复制代码


3、判断类方法

1.Optional.isPresent()

/**	判断是否存在值*/public boolean isPresent() {    return value != null;}
复制代码

2.Optional.ifPresent(Consumer<? super T> consumer)

/**	如果存在值,则使用该值执行给定的操作,否则不执行任何操作。        参数:Consumer要执行的动作*/public void ifPresent(Consumer<? super T> action) {    if (value != null) {        action.accept(value);    }}
复制代码

3.Optional.ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)

/**				如果存在值,则使用该值执行给定的操作,否则执行给定的基于空的操作。        参数:动作–要执行的动作(如果存在值)emptyAction –要执行的基于空的操作(如果不存在任何值)        抛出:如果存在一个值并且给定的操作为null ,或者不存在任何值并且给定的基于空的操作为null ,        则抛出NullPointerException;
*/public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) { if (value != null) { action.accept(value); } else { emptyAction.run(); }}
复制代码


4.示例代码

public void ifTest03(){Trade trade = Trade.builder ().iCode ("qyz0711").iName ("青衣醉 0711").iType ("0711").build ();Trade defaultTrade = Trade.builder ().iCode ("MR1016").iName ("默认值").iType ("1016").build ();Optional<Trade> tradeInfoEmptyOpt = Optional.empty();Optional<Trade> tradeInfoOpt = Optional.of(trade);// 1、isPresent()-> 判断是否存在对象,我们在调用 get 之前,一定要先调用 isPresent,因为直接如果 value 是 null,直接调用 get 会报异常;if (tradeInfoEmptyOpt.isPresent ()) {Trade trade1 = tradeInfoOpt.get ();System.out.println ("isPresent():"+trade1);}else {System.out.println ("isPresent(): null");}//2、ifPresent(Consumer<? super T> consumer)->如果存在值,则使用该值执行给定的操作,否则不执行任何操作。tradeInfoOpt.ifPresent (trade2 -> {System.out.println("ifPresent(Consumer<? super T> consumer):"+trade2);});


 public void ifTest03(){        Trade trade = Trade.builder ()                .iCode ("qyz0711")                .iName ("青衣醉0711")                .iType ("0711")                .build ();        Trade defaultTrade = Trade.builder ()                .iCode ("MR1016")                .iName ("默认值")                .iType ("1016")                .build ();        Optional<Trade> tradeInfoEmptyOpt = Optional.empty();        Optional<Trade> tradeInfoOpt = Optional.of(trade);        // 1、isPresent()-> 判断是否存在对象,我们在调用get之前,一定要先调用isPresent,因为直接如果value是null,直接调用get会报异常;        if (tradeInfoEmptyOpt.isPresent ()) {            Trade trade1 = tradeInfoOpt.get ();            System.out.println ("isPresent():"+trade1);        }else {            System.out.println ("isPresent(): null");        }        //2、ifPresent(Consumer<? super T> consumer)->如果存在值,则使用该值执行给定的操作,否则不执行任何操作。        tradeInfoOpt.ifPresent (trade2 -> {            System.out.println("ifPresent(Consumer<? super T> consumer):"+trade2);        });
//3、ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) -> 如果存在值,则使用该值执行给定的操作,否则就执行为空是的操作。 tradeInfoOpt.ifPresentOrElse (trade3 -> { System.out.println("ifPresentOrElse():"+"trade3 is not null,"+trade3); },()->{ System.out.println("ifPresentOrElse():"+"value is null"); }); }
复制代码


4、过滤类方法

1.Optional<T> filter(Predicate<? super <T> predicate)

/**		如果存在一个值,并且该值与给定的(predicate方法)匹配,则返回描述该值的Optional ,否则返回一个空的Optional 。    */public Optional<T> filter(Predicate<? super T> predicate) {    Objects.requireNonNull(predicate);    if (!isPresent()) {        return this;    } else {        return predicate.test(value) ? this : empty();    }}
复制代码

2.示例代码

@Testpublic void filterTests(){    //Optional<T> filter(Predicate<? super T> predicate)->如果存在一个值,并且该值与给定的(predicate方法)匹配,    // 则返回描述该值的Optional ,否则返回一个空的Optional 。    Optional<Object> o = Optional.ofNullable ("3333");    System.out.println ("filter(predicate):"+o);    Optional<Object> o2 = o.filter (o1 -> false);    Optional<Object> o3 = o.filter (o1 -> true);    System.out.println ("filter(predicate),predicate=false:"+o2);    System.out.println ("fiilter(predicate),predicate=true:"+o3);}
复制代码


5.映射类方法

1.<U>Optional<U> map(Function<? super T,? extends U> mapper)

/**        map方法接受一个映射函数参数,返回一个被Optional包装的结果。若结果为空,则返回 空Optional 。        如果映射函数返回null结果,则此方法返回空的Optional         返回值类型:Optional对象     */    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));        }    }
复制代码

2.<U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)

/**       flatMap 方法则要求入参中的函数式接口返回值本身就是 Optional 对象。        返回值:施加的结果Optional可以映射函数此的值Optional ,如果一个值存在,否则一个空Optional        抛出:NullPointerException如果映射函数为null或返回null结果        
*/ public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) { return empty(); } else { @SuppressWarnings("unchecked") Optional<U> r = (Optional<U>) mapper.apply(value); return Objects.requireNonNull(r); } }
复制代码


3.map 与 flatmap 的区别及示例代码

相同点:两个方法的返回值都是 Optional 对象!

不同点:区别在于调用两个方法需要的传入参数(函数式接口)的返回值不同,

map 方法会自动将入参中的函数式接口返回值包装成 Optional 对象,而 flatMap 方法则要求入参中的函数式接口返回值本身就是 Optional 对象。

入参的不同也就导致了使用场景的不同,如果函数式接口返回值本身就是 Optional 对象,那么就可以直接使用 flatMap 方法,否则就应该使用 map 方法,省去了使用 Optional 包装的麻烦。

比如示例中 toString 返回值是 String 类型,那么此时使用 map 方法更合理。

 @Test    public void mapTest(){        Trade trade = new Trade ("qyz0711", "青衣醉0711", "0711");        //1、map(Function<? super T,? extends U> mapper)->如果存在value,则通过mapper方法处理,        // 映射称该值结果并返回,结果类型还是为Optional包装的对象;若不存在这返回空的Optional对象        Optional<Trade> optionalTrade = Optional.of (trade);        Optional<String> s = optionalTrade.map (Trade::toString);        System.out.println (s);        System.out.println (s.get ());
//2、flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) Optional<Trade> optionalTrade2 = Optional.of (trade); Optional<String> s1 = optionalTrade2.flatMap (trade1 -> { return Optional.ofNullable (trade1.getICode ()); });
}
复制代码


发布于: 刚刚阅读数: 4
用户头像

echoes

关注

探索未知,分享收获 2018.04.25 加入

还未添加个人简介

评论

发布
暂无评论
Optional的使用详解_echoes_InfoQ写作社区