Java Optional 使用心得

core-java
标签: #<Tag:0x00007f1d27c1bf60>

#1

关于 Optional 的一些知识点

  • Optional 是帮助我们简化非空判断操作的.
  • 通过of, ofNullable方法可以得到一个 Optional
  • Optional使用链式调用风格, 可以对 Optional 做一些操作.

常用方法

of, ofNullable

  • 我不推荐使用of(), 应为如果传入的参数是 null, 会直接报错NullPointerException.
  • ofNullable是最常用的方法, 用来构造一个 Optional 对象.
public static <T> Optional<T> ofNullable(T value)
public static <T> Optional<T> of(T value)

例子

System.out.println(Optional.ofNullable(“abcd").isPresent()); //打印 true
System.out.println(Optional.of(null).isPresent()); //抛出NullPointerException异常

isPresent()

  • isPresent() 没有参数, 仅仅返回 boolean, 判断是否为空.
public boolean isPresent()
System.out.println(Optional.ofNullable(null).isPresent());
//这个并不是个好例子, 因为如果只是想要判断是否为 null 用 xxx == null 更加方便

ifPresent(Consumer<? super T> consumer)

  • ifPresent(Consumer<? super T> consumer) 没有返回值, 并且参数是一个 Consumer. 只有值不是 null 才执行accept()方法, 否则什么都不做.
public void ifPresent(Consumer<? super T> consumer)
public interface Consumer<T> {
    void accept(T t);
}

例子

Optional.<String>ofNullable(null).ifPresent(System.out::println);

orElse, orElseGet, orElseThrow

  • 这三个方法都是当 Optional 的值为空时才执行相应的操作, 如果值不为空, 则返回原值

这个方法会返回传入的参数, 如果 Optional的值为空. 否则返回原值.

public T orElse(T other) 

例子

System.out.println(Optional.ofNullable(null).orElse("value is null"));

这个方法会执行 get 方法并返回值, 如果 Optional 的值为空, 如果值不为空则返回原值

public T orElseGet(Supplier<? extends T> other)
public interface Supplier<T> {
    T get();
}

例子

System.out.println(Optional.ofNullable(null).orElseGet(()-> "value is null"));

这个方法将抛出指定异常, 如果 Optional 的值为空, 如果值不为空则返回原值

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
public interface Supplier<T> {
    T get();
}

例子

System.out.println(Optional.ofNullable(null)
        .orElseThrow(() -> new IllegalArgumentException("value cannot be null")));

map

  • 如果 Optional 的值为 null, 返回一个空 Optional 对象Optional.empty()
  • 如果 Optional 的值不为 null, 则调用Function的 apply 方法, 并返回一个值为 apply 方法返回值的 Optional 对象
public<U> Optional<U> map(Function<? super T, ? extends U> mapper)
public interface Function<T, R> {
    R apply(T t);
}

例子

String string = null;
Integer i = Optional.ofNullable(string).map(Integer::new).orElse(0);
// i 值为 0
String string = "12";
Integer i = Optional.ofNullable(string).map(Integer::new).orElse(0);
// i 值为 12

flatMap

  • 把对象中的某个属性转为 Optional, 然后返回
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
public interface Function<T, R> {
    R apply(T t);
}

例子

List<Car> cars = new ArrayList<>();
cars.add(new Car("abcdefg", 1230000));

return Optional.ofNullable(cars)
        .filter(cars1 -> cars.size() > 0)
        .flatMap(cars1 -> Optional.ofNullable(cars1.get(0)))
        .map(car -> car.getName())
        .orElse("no cars");

filter

  • 如果 Optional 的值为 null, 不做任何操作, 并返回这个 Optional 对象.
  • 如果 Optional 的值为不为 null, 则调用Predicate的 test 方法,
    • 如果 test 返回 true, 则返回 当前Optional 对象
    • 如果 test 返回 false, 返回一个空 Optional 对象(Optional.empty()).
public Optional<T> filter(Predicate<? super T> predicate)
public interface Predicate<T> {
    boolean test(T t);
}

例子

System.out.println(Optional.<String>ofNullable("abc")
    .filter(string -> "abc".equals(string))
    .orElse("value not equals abc"));
//打印 abc
System.out.println(Optional.<String>ofNullable("bcd")
    .filter(string -> "abc".equals(string))
    .orElse("value not equals abc"));
//打印 value not equals abc

get

这个方法不推荐使用, 因为如果 Option 的值为空, 会报异常NoSuchElementException.

public T get()

例子

System.out.println(Optional.ofNullable("Abc").get()); //打印 Abc
System.out.println(Optional.ofNullable(null).get()); //抛出异常

常用操作的例子

  • 我们在写一些工具方法时, 比如类型转换方法. 经常要先判断传入的参数是否为空, 然后再对参数进行转换操作. 然后返回转换后的值, 或者默认值, 或者抛出我们自定义的异常. Optional 可以帮助我们简化这个过程.
    比如上边出现过的例子
String string = "12";
Integer i = Optional.ofNullable(string).map(Integer::new).orElse(0);

Integer i = Optional.ofNullable(string)
        .map(Integer::new)
        .orElseThrow(() -> new IllegalArgumentException("string cannot be null"));
  • 使用Optional 做校验操作.Optional的链式调用可以方便我们实现多个条件
Optional.ofNullable("abc@abc.com")
        .filter(string -> string.indexOf("@") > 0)
        .filter(string -> string.indexOf(".com") > 0)
        .orElseThrow(() -> new IllegalArgumentException("Invalid email address"));

使用心得:

  • 应尽量避免使用Optional.get()方法 和 Optional.of() 方法, 因为我们使用Optional的一个重要原因就是要避免空指针异常, 但是以上两个方法仍然会发生空指针异常.

  • 可以使用 orElse方法代替 get 方法, 使用ofNullable方法代替 of 方法.

  • isPresent()这个方法虽然本身并没有问题, 不过我们使用Optional 的初衷是为了简化代码, 避免做非空的判断. 那么这个方法就显得有些多余. 当你真的需要用到这个方法是, 有时 obj == null 可能是更好的选择.

  • 对于 Optional, 我们更应把它视为一种操作, 而不是属性或参数. 也就是说不应该把 Optional 做为方法的传入参数或返回值, 或类的属性. 当我们需要对一个参数或属性做某些操作时, 先把这个参数转换为 Optional(比如用ofNullable方法 ), 操作完成后再返回一个指定的类型(比如使用 orElse 方法), 而不是 Optional 自己.

参考

使用 Java8 Optional 的正确姿势 | 隔叶黄莺 Unmi Blog - 软件编程实践
Java8 如何正确使用 Optional - ImportNew