概述 相信每个java程序员都曾经在编码的过程中遇到过NullPointerException,毕竟在程序运行期间,谁也不能百分百保证当前正在调用的对象一定不为null。本文要介绍的是java 1.8新加入的一个类Optional
,使用它我们就可以在代码中优雅的处理null,避免了大量if (o == null)
这种操作,同时最大限度避免程序在运行时抛出NullPointerException
原理 Optional处理null的原理很简单,我们可以把Optional当做是一个容器,它仅仅包含了某个将要被处理的对象,当然了这个对象可能是null也可能不是null,例如当我们调用:Optional.ofNullable(value)
方法后,一个Optional实例就被创建完成了,接下来我们就不用关心这value是不是null,只需要调用Optional提供的方法,传入一些FunctionalInterface
,只有当value不为null时 ,这些FunctionalInterface
才会被执行。接下来我们看一下它的源码
Optional源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 package java.util;import java.util.function.Consumer;import java.util.function.Function;import java.util.function.Predicate;import java.util.function.Supplier;public final class Optional <T> { private static final Optional<?> EMPTY = new Optional <>(); private final T value; private Optional () { this .value = null ; } public static <T> Optional<T> empty () { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; } private Optional (T value) { this .value = Objects.requireNonNull(value); } public static <T> Optional<T> of (T value) { return new Optional <>(value); } public static <T> Optional<T> ofNullable (T value) { return value == null ? empty() : of(value); } public T get () { if (value == null ) { throw new NoSuchElementException ("No value present" ); } return value; } public boolean isPresent () { return value != null ; } public void ifPresent (Consumer<? super T> consumer) { if (value != null ) consumer.accept(value); } public Optional<T> filter (Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this ; else return predicate.test(value) ? this : empty(); } 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)); } } 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)); } } public T orElse (T other) { return value != null ? value : other; } public T orElseGet (Supplier<? extends T> other) { return value != null ? value : other.get(); } public <X extends Throwable > T orElseThrow (Supplier<? extends X> exceptionSupplier) throws X { if (value != null ) { return value; } else { throw exceptionSupplier.get(); } } @Override public boolean equals (Object obj) { if (this == obj) { return true ; } if (!(obj instanceof Optional)) { return false ; } Optional<?> other = (Optional<?>) obj; return Objects.equals(value, other.value); } @Override public int hashCode () { return Objects.hashCode(value); } @Override public String toString () { return value != null ? String.format("Optional[%s]" , value) : "Optional.empty" ; } }
Optional的源码很简单,内部方法执行的逻辑都是基于Optional包含的对象不为null的情况下才会执行,极大的减少了程序运行期间抛出的NullPointerException同时也使得我们编码的方式变得更加的优雅。里面有两个比较相似的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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)); } } 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方法,它的入参返回类型是U类型的。最后return又重新对这个U类型的结果进行包装了一次,所以最终方法返回类型是Optional。再来看一下flatMap方法,它的入参返回类型是Optional<U>
类型的,最终的方法返回值就是Function执行返回的结果,也就是Optional,所以从本质上来讲这个两个方法返回的结果是一样的,都返回了Optional对象,区别在于如果我们调用了map方法,不需要手动创建一个新的Optional,但是如果调用了flatMap方法,我我们就需要手动返回一个Optional对象了
例子 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import org.apache.commons.lang3.StringUtils;import java.util.HashMap;import java.util.Map;import java.util.Optional;import java.util.function.Supplier;public class Person { private String phoneNumber; private static Map<String, Person> map = new HashMap <>(); public static String getPerson (String name) { return Optional.ofNullable(name) .filter(StringUtils::isNotBlank) .map(n -> map.get(n)) .flatMap(person -> Optional.of(person.getPhoneNumber())) .orElseThrow(new PersonException ("该用户手机号为空" )) ; } public String getPhoneNumber () { return phoneNumber; } public static class PersonException extends RuntimeException implements Supplier <PersonException> { PersonException(String message) { super (message); } @Override public PersonException get () { return this ; } } }
根据用户名查询用户信息
Optional.ofNullable(name) Optional<String>
filter(StringUtils::isNotBlank)
Optional<String>
如果name本身就是null的话,返回Optional本身
如果name不为null,并且Predicate执行返回true,返回本身,否则返回一个空的Optional
map(n -> map.get(n))
Optional<Person>
flatMap(person -> Optional.of(person.getPhoneNumber()))
Optional<String>
获取用户的手机号码,注意这里手动创建了一个新的Optional对象
orElseThrow(new PersonException("该用户手机号为空"))
总结
Optional可以看做是一个容器,内部维护一个对象指向将要被处理的可能为null的值
Optional在执行各个方法前会先判断内部维护的这个对象是否为null,最大限度的避免NullPointerException的出现