Optional类应用
介绍
Optional类是JAVA8新增的一个容器类,位于java.util包下。容器类可以理解为一个Optional的实例中包含一个对象实例,然后这个容器类提供一些对这个对象操作的方法,Optional在防止空指针方面得到了广泛的运用。下面会在Optional类和实际运用的时机来介绍。
类的构造和方法剖析
构造方法
Optional类一共有两个构造方法
1.私有的构造方法,给value赋一个空值,不对外开放
/**
* 构造一个空实例。
* 通常每个虚拟机只应存在一个空实例
*/
private Optional() {
this.value = null;
}
2.构造一个有值的实例,如果传入的值为空则会抛出NullPointerException异常,同样不对外开放。
/**
* 构造一个存在值的实例。
* @param value要存在的非空值。
* @throws 如果值为null,则会抛出NullPointerException异常。
*/
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
成员变量
Optional一共有两个成员变量 “value” 和 “EMPTY” 。value是Optional实例包含的值,EMPTY是value为空的Optional实例。
/**
* empty()方法返回的公共实例。
*/
private static final Optional<?> EMPTY = new Optional<>();
Optional对象中包裹的值。
private final T value;
成员方法
Optional的成员方法大概可以分为三个类型 “取值” 、 “判断” 和 “构造实例”,下面会逐一介绍。
取值类型方法
-
get()方法,获取该Optional实例中的包装的值,如果包装值不存在则会抛出NoSuchElementException,如果存在直接返回该值。
/** * 如果此{@code Optional}中存在值,则返回该值,否则就会抛出NoSuchElementException。 * @return 此{@code Optional}持有的非空值。 * @throws 如果不存在值,则会抛出NoSuchElementException。 * @see Optional#isPresent() */ public T get() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; }
-
orElse(T other)方法,获取Optional实例中的包装值,如果值为空则返回other。
/** * 返回值(如果存在),否则返回{@code other}。 * * @param 如果value为空则返回other值,other仍然可能为空 * @return 如果value存在则返回value,如果value不存在返回other */ public T orElse(T other) { return value != null ? value : other; }
-
orElseGet(Supplier<? extends T> other)方法,同orElse()方法差不多,区别是orElse()方法如果value不存在返回的是传入的方法参数other,而orElseGet()返回的是传入的函数 ”Supplier“ get之后的结果。
/** * 如果value存在则返回value,如果value不存在则返回 Supplier调用的结果值 * @param 生产者模式的函数,如果value不存在则返回其结果。 * @return value存在则返回value,不存在则返回Supplier的计算结果。 * @throws 如果value和other都为空则抛出NullPointerException */ public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); }
这个方法必须要有java8的函数式接口的知识才能使用,下面举个例子:
执行结果:
-
orElseThrow(Supplier<? extends X> exceptionSupplier)方法,这个方法的特性是如果value不为空则返回value,如果value为空则通过参数 exceptionSupplier 计算出一个异常类的实例然后抛出。
/** * 如果value存在返回value,如果value不存在则会引发异常,异常实例是由参数exceptionSupplie计算而来。 * @param 构造异常的工厂模式函数 * @return 当前Optional实例的value * @throws 如果value不存在则会引发异常 * @throws 如果value和exceptionSupplier都不存在则会引发NullPointerException异常。 */ public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); } }
这个方法跟orElseGet(Supplier<? extends T> other)方法用法相当同样也需要函数式编程的基础,下面举个例子
结果:
-
ofNullable()方法,该方法的作用是构造一个value可以为空Optional实例
/** * 如果value非空则返回一个包含value值的Optional实例,如果为空则返回一个包含空value的Optional的实例。 * @param <T> 类型的值 * @param value值,可能为空 * @return 返回一个Optional实例。 */ public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); }
-
of(T value)方法,of方法其实就是调用了内部的Optional(T value)构造函数,所以value不能为空,否则会抛出NullPointerException。
/** * 使用指定的当前非空值返回{@code Optional}。 * @param <T> 类型的值 * @param value要存在的值,该值必须非空 * @return 值存在的{@code Optional} * @throws 如果value为空抛出NullPointerException。 */ public static <T> Optional<T> of(T value) { return new Optional<>(value); }
-
empty()方法,该方法的作用是返回一个空的Optional实例,该实例是Optional类中的静态成员变量。
/** * 返回一个空的Optional实例 * @return 空的Optional实例 */ public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }
-
map(Function<? super T, ? extends U> mapper) 方法,该方法的作用是通过Function函数接口将T经过计算后转为U的方法,其中U会被包装为Optional类型返回。
/** * 如果某个值存在,则将提供的映射函数应用于该值,如果结果为非null,则返回一个{@code Optional}来描述结果。否则返回一个空的{@code Optional}。 * @param <U> 映射函数结果的类型 * @param mapper应用于值的映射函数(如果存在) * @return {@code Optional}描述将映射函数应用于此{@code Optional}的值的结果(如果存在值),否则为空{@code Optional} * @throws 如果映射函数为null,则发生NullPointerException */ 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)); } }
-
flatMap(Function<? super T, Optional> mapper) 方法,该方法的作用是和map()方法差不多,只不过flatMap中Function函数的参数泛型必须为Optional类型,但是返回的时候不在包装一层Optional。
/** * 将T通过mapper为U,但是U必须是Optional包装的。 * @param <U> 返回的{@code Optional}的类型参数 * @param mapper应用于值的映射函数(如果存在映射函数) * @return 如果存在值,则将{@code Optional}的值应用{@code Optional}承载映射函数的结果,否则为空{@code Optional} * @throws 如果映射函数为null或返回空结果,则为NullPointerException */ 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)); } }
判断类型
-
isPersend()方法,该方法的作用是判断value是否为空如果为空返回false否则返回true。
/** * 如果存在值,则返回{@code true},否则返回{@code false}。 * @return 如果存在值{@code true},则为{@code false}。 */ public boolean isPresent() { return value != null; }
-
ifPersend(Consumer<? super T> consumer)方法作用是如果存在值则通过consumer函数消费这个值,否则什么都不做。
/** * 如果存在值,会通过函数消费该值,否则不做任何操作。 * @param 消费者函数 * @throws 如果value和函数都为空则抛出NullPointerException。 */ public void ifPresent(Consumer<? super T> consumer) { if (value != null) consumer.accept(value); }
该方法需要掌握函数式编程才能熟练运用,下面是例子
结果:控制台输出了哆啦A梦
- filter(Predicate<? super T> predicate)方法,该方法的作用是先通过isPersend()方法判断value是否为空,如果value为空则返回当前实例。如果value不为空则使用predicate(value)函数验证value,如果验证结果为true则返回当前Optional实例,如果验证失败则返回空实例。
/**
* 如果存在一个值,并且该值与给定的谓词匹配,则返回一个描述该值的{@code Optional},否则返回一个空的{@code Optional}。
* @param 如果value存在则将value应用于判断函数进行判断
* @return 如果判断结果为true那么返回当前Optional实例否则返回空实例。
* @throws 如果判断函数为空则抛出NullPointerException
*/
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
下面是例子
结果:
脑图
详细脑图地址:http://huatu.98youxi.com/swdt/#R7b18cd527400c284d7ee73f555befedb
总结
Optional已经介绍完了,用好这个类可以有效的避免空指针的尴尬,也可以通过链式调用提升代码的美观度和可读性,jdk9又为该类提供了新的方法,但是此文章只针对jdk8进行讲解,有好奇的伙伴可以去在行查阅。 最后给点个赞吧~
最后会将本文章的markdown文件笔记送给大家。 笔记:http://shaohua-blog.oss-cn-beijing.aliyuncs.com/note/Optional类应用.md