你的位置:首页 > Java教程

[Java教程]JAVA 8 Optional类介绍及其源码

什么是Optional对象

Java 8中所谓的Optional对象,即一个容器对象,该对象可以包含一个null或非null值。如果该值不为null,则调用isPresent()方法将返回true,且调用get()方法会返回该值。

另外,该对象还有其它方法:

如可以使用orElse()方法给Optional对象设定默认值(当值为null时,会使用默认值);

使用ifPresent()方法来执行一段代码(当值不为null时,执行代码段)。

Optional主要被用于Java 8的Stream中,简单举个例子:

package optional;import java.util.Optional;import java.util.stream.Stream;public class Snippet{  public static void main(String[] args)  {    Stream<String> names = Stream.of("Lamurudu", "Okanbi", "Oduduwa");        Optional<String> startswl = names.filter(name -> name.startsWith("L")).findFirst();        //判断是否不为null    if(startswl.isPresent()){      System.out.println(startswl.get());    }        //if值为null:打印“null”;if值不为null:打印原值    System.out.println(startswl.orElse("null"));    //if值不为null,执行Lambda表达式    startswl.ifPresent(name -> {      String s = name.toUpperCase();      System.out.println(s);    });  }}

使用Optional对象的好处

减少NullPointerException异常

写出更加优雅的代码

源码及示例

Optional类的属性和方法如下:

 

我们一个个看,先看两个成员属性;

成员属性

如下,一个是EMPTY常量,即存放空值的Optional对象,另一个是value,即被存放的值,可为null或非null值;

  /**   * Common instance for [email protected] empty()}.   */  private static final Optional<?> EMPTY = new Optional<>();  /**   * If non-null, the value; if null, indicates no value is present   */  private final T value;

构造方法

两个构造方法,注意都是私有的

1、创建一个包含空值的Optional对象;

2、创建一个非空值的Optional对象;

  private Optional() {    this.value = null;  }

  private Optional(T value) {    this.value = Objects.requireNonNull(value);  }

empty()方法

这个方法很简单,作用是返回一个Optional实例,里面存放的value是null,源码如下:

  public static<T> Optional<T> empty() {    @SuppressWarnings("unchecked")    Optional<T> t = (Optional<T>) EMPTY;    return t;  }

of(T value)方法

很简单,就是返回一个包含非空值的Optional对象

  public static <T> Optional<T> of(T value) {    return new Optional<>(value);  }

ofNullable(T value)方法

 很简单,返回一个可以包含空值的Optional对象

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

get()方法

 得到Optional对象里的值,如果值为null,则抛出NoSuchElementException异常

  public T get() {    if (value == null) {      throw new NoSuchElementException("No value present");    }    return value;  }

isPresent()方法

很简单,判断值是否不为null

  public boolean isPresent() {    return value != null;  }

ifPresent(Consumer<? super T> consumer)方法

 当值不为null时,执行consumer

  public void ifPresent(Consumer<? super T> consumer) {    if (value != null)      consumer.accept(value);  }

举个例子,ifPresent方法执行Lambda表达式,将值转换为大写并打印:

package optional;import java.util.Optional;public class Snippet{  public static void main(String[] args)  {    Optional<String> test = Optional.ofNullable("abcDef");        //值不为null,执行Lambda表达式,    test.ifPresent(name -> {      String s = name.toUpperCase();      System.out.println(s);    });    //打印ABCDEF  }}

filter(Predicate<? super T> predicate)方法

看方法名就知道,该方法是过滤方法,过滤符合条件的Optional对象,这里的条件用Lambda表达式来定义,

如果入参predicate对象为null将抛NullPointerException异常,

如果Optional对象的值为null,将直接返回该Optional对象,

如果Optional对象的值符合限定条件(Lambda表达式来定义),返回该值,否则返回空的Optional对象

源码如下:

  public Optional<T> filter(Predicate<? super T> predicate) {    Objects.requireNonNull(predicate);    if (!isPresent())      return this;    else      return predicate.test(value) ? this : empty();  }

使用示例:

package optional;import java.util.Optional;public class Snippet{  public static void main(String[] args)  {    Optional<String> test = Optional.ofNullable("abcD");        //过滤值的长度小于3的Optional对象    Optional<String> less3 = test.filter((value) -> value.length() < 3);    //打印结果    System.out.println(less3.orElse("不符合条件,不打印值!"));  }}

map(Function<? super T, ? extends U> mapper)方法

 前面的filter方法主要用于过滤,一般不会修改Optional里面的值,map方法则一般用于修改该值,并返回修改后的Optional对象

如果入参mapper对象为null将抛NullPointerException异常,

如果Optional对象的值为null,将直接返回该Optional对象,

最后,执行传入的lambda表达式,并返回经lambda表达式操作后的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));    }  }

使用示例:

package optional;import java.util.Optional;public class Snippet{  public static void main(String[] args)  {    Optional<String> test = Optional.ofNullable("abcD");        //将值修改为大写    Optional<String> less3 = test.map((value) -> value.toUpperCase());    //打印结果 ABCD    System.out.println(less3.orElse("值为null,不打印!"));  }}

flatMap(Function<? super T, Optional<U>> mapper)方法

flatMap方法与map方法基本一致,唯一的区别是,

如果使用flatMap方法,需要自己在Lambda表达式里将返回值转换成Optional对象,

而使用map方法则不需要这个步骤,因为map方法的源码里已经调用了Optional.ofNullable方法;

源码:

  public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {    Objects.requireNonNull(mapper);    if (!isPresent())      return empty();    else {      return Objects.requireNonNull(mapper.apply(value));    }  }

使用示例:

package optional;import java.util.Optional;public class Snippet{  public static void main(String[] args)  {    Optional<String> test = Optional.ofNullable("abcD");        //使用flatMap,将值修改为大写    Optional<String> less3 = test.flatMap((value) -> Optional.ofNullable(value.toUpperCase()));    //使用map,将值修改为大写    //Optional<String> less3 = test.map((value) -> value.toUpperCase());        //打印结果 ABCD    System.out.println(less3.orElse("值为null,不打印!"));  }}

orElse(T other)方法

很简单,当值为null时返回传入的值,否则返回原值;

源码:

  public T orElse(T other) {    return value != null ? value : other;  }

orElseGet(Supplier<? extends T> other)方法

功能与orElse(T other)类似,不过该方法可选值的获取不是通过参数直接获取,而是通过调用传入的Lambda表达式获取

源码:

  public T orElseGet(Supplier<? extends T> other) {    return value != null ? value : other.get();  }

使用示例:

package optional;import java.util.Optional;public class Snippet{  public static void main(String[] args)  {    Optional<String> test = Optional.ofNullable(null);    System.out.println(test.orElseGet(() -> "hello"));    //将打印hello  }}

orElseThrow(Supplier<? extends X> exceptionSupplier)方法

当遇到值为null时,根据传入的Lambda表达式跑出指定异常

源码

  public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {    if (value != null) {      return value;    } else {      throw exceptionSupplier.get();    }  }

使用示例:

package optional;import java.util.Optional;public class Snippet{  public static void main(String[] args)  {    Optional<String> test = Optional.ofNullable(null);    //这里的Lambda表达式为构造方法引用    System.out.println(test.orElseThrow(NullPointerException::new));    //将打印hello  }}

参考资料

jdk1.8.0_31源码

https://blog.idrsolutions.com/2015/04/java-8-optional-class-explained-in-5-minutes/

https://www.voxxed.com/blog/2015/05/why-even-use-java-8-optional/

http://unmi.cc/proper-ways-of-using-java8-optional/