详解Optional类
前言
- 最近在看《阿里编程规范》,发现之前写过很多“糟糕”的代码,各种if,else满天飞,《规范》里给了很多方式来优化我们的代码,而Optional类很好的解决了null 值判断的问题。
- 之前对于Java8的特性只停留在理论部分,从来没有想过在自己的代码里用过。但是最近用了Optional之后可以说是欲罢不能,简直是装杯神器,终于可以稍微“优雅”的编程了。
简介
-
上面就说了Optional是为了解决null值判断,让我们可以避免显式的null值判断。
我们先来看一小段“糟糕”的代码:
public String getName(Person person){ if(null == person){ return "没有人"; } return person.getName(); }
我们再来看看用Optional优化过的代码:
public String getName(Person person){ return Optional.ofNullable(person).map(p -> p.getName()).orElse("没有人"); }
根本不用我多说,利用Optional和lambda表达式优化后的代码变得更加的简洁和优雅。
详解
-
结构
我们先来看看Optional类的结构:
可以看出来其构造函数都是私有的,所以不能通过new来构建它,接下来以这张结构图为目录详细介绍一下Optional类。
-
创建Optional对象
Optional提供了三个静态方法来创建对象,如下所示:
// 创建一个包装对象值为空的Optional对象 Optional<String> opt1 = Optional.empty(); // 创建包装对象值非空的Optional对象 Optional<String> opt2 = Optional.of("optional"); // 创建包装对象值允许为空的Optional对象 Optional<String> opt3 = Optional.ofNullable(null);
-
Optional类提供方法的用法
-
get()
- 源码:
public T get() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; }
-
介绍:
返回包装对象实际值,为null抛出NoSuchElementException异常。
-
isPresent()
- 源码:
public boolean isPresent() { return value != null; }
-
介绍:
判断包装对象是否为空。这个方法要慎用,不然我们直接用null值判断不就行了。
-
ifPresent()
- 源码:
public void ifPresent(Consumer<? super T> consumer) { if (value != null) consumer.accept(value); }
- 例:
public void printName(Person person){ Optional.ofNullable(person).ifPresent(p -> System.out.println(p.getName())); }
-
介绍:
例子打印了人的姓名,这样就不用null判断啦,Optional已经帮我们做啦。
-
filter()
- 源码:
public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); }
- 例子:
public static void filterAge(Person person){ Optional.ofNullable(person).filter( p -> p.getAge() > 18).ifPresent(p -> System.out.println(p.getName)); }
-
介绍:
例子打印了大于18岁人的名字。
-
map()
- 源码:
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)); } }
-
介绍:
简介里的例子已经用到了这个方法,例子里会返回Optional,一个新的包装对象,而不是Optional。
-
flatMap()
- 源码:
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)); } }
-
介绍:
我们对比map()方法,发现flatMap()的入参变了,所以说 map()是把结果自动封装成一个Optional,但是flatMap()需要你自己去封装 。
-
orElse()
- 源码:
public T orElse(T other) { return value != null ? value : other; }
-
介绍:
这个就比较简单了,简介的例子也用到了,就是简单的一个else判断。
-
orElseGet()
- 源码:
public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); }
- 例子:
public String getGender(Person person){ return Optional.ofNullable(person).map(p -> p.getName()).orElseGet(() -> "没有人"); }
-
介绍:
orElseGet()方法与orElse()方法类似,区别在于orElseGet()方法的入参为一个Supplier对象,用Supplier对象的get()方法的返回值作为默认值 。
-
orElseThrow()
- 源码:
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); } }
- 例子
public String getGender1(Person person){ return Optional.ofNullable(person).map(p -> p.getName()).orElseThrow(() -> new RuntimeException("没有人")); }
-
介绍:
orElseThrow()方法就跟orElseGet()方法非常相似了, 只不过要抛出异常,orElseThrow()方法主要用在包装对象值为空时需要抛出特定异常的场景 。
-
注意事项
- 上面详解的时候我也提到了一些,那就是get()和isPresent()要慎用啊,这样才能让我们的代码更加的优雅,当然也有一些情况会用到,比如Optional空和非空都需要进行很多操作。反正我们得充分发挥Optional的作用,不然太浪费这个装杯神器了。