Optional类的方法
方法 | 描述 |
---|---|
empty | 返回一个空的Optional类实例 |
of | 将对象封装到Optional类中去,要求对象不能够为空,否则返回一个NullPointerException |
ofNullable | 获取得到Optional类封装的对象,如果对象为空,那么返回一个空实例,如果不为空,返回一个封装了对象的Optional实例 |
filter | 如果值存在而且能够满足提供的谓词,就返回包含该值的Optional对象,否则返回一个空的Optional类实例 |
map | 如果Optional类封装的值存在,那么执行map函数中定义的内容 |
flatMap | 如果该值存在,通过Function函数,返回一个Optional类型的值,否则返回一个空的Optional类实例 |
get | 如果值存在,那么将Optional类实例封装的值返回,否则将会抛出NoSuchElementException异常 |
isPresent | 如果存在封装的对象,那么返回true;如果不存在,那么返回false |
ifPresent | 如果存在封装的对象,那么执行后面的消费方法;如果不存在,那么不做任何事情 |
orElse | 如果Optional实例对象是empty,那么使用默认的值来代替 |
orElseGet | 如果有值,则获取得到将其返回;如果没有值,那么将会使用指定的函数生成的值 |
orElseThrow | 如果有值将其进行返回,否则抛出一个指定的异常 |
之前写过一篇Optional类的说明,但是感觉不同情况下有不同的用法,所以现在结合源码再将使用场景结合一下使用。
/*** 可能包含也可能不包含非空值的容器对象。 如果存在值,isPresent() 将返回 true,get() 将返回该值。 提供了依赖于包含值的存在与否的其他方法,例如 orElse()(如果值不存在则返回默认值)和 ifPresent()(如果值存在则执行代码块)。 这是一个基于值的类; 在 Optional 实例上使用身份敏感操作(包括引用相等 (==)、身份哈希码或同步)可能会产生不可预测的结果,应该避免。 所以可以将这个类的实例理解成是一个对值做处理的容器 */ public final class Optional<T> { // 空实例对象,虽然对象有值,但是对于属性来说是没有的。因为这里没有对值的任何操作 private static final Optional<?> EMPTY = new Optional<>(); /** * If non-null, the value; if null, indicates no value is present 如果value为null,说明没有值。如果要是和上面的来进行对应,那么就是上面的EMPTY实例的value就是一个null 泛型是类上指明了的,传入进来的是什么类型的,那么使用的时候就可以使用什么样的类型。 */ private final T value; /** 从这里可以验证。EMPTY的value为null,private关键字修饰的,外界无妨通过实例化对象 */ private Optional() { this.value = null; } // 对于当前的这个对象来说,value为null。然后将这个对象返回,最终操作的是value,显然value是为null的。 public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; } // 这里的构造方法显然返回的是一个value为非null的Optional对象。因为如果是null,那么就直接抛出空指针异常了。 private Optional(T value) { this.value = Objects.requireNonNull(value); } // 传入的值不能是Null,否则抛出NullPointerException异常 public static <T> Optional<T> of(T value) { return new Optional<>(value); } // 如果value的值为null,然后直接返回value为null的对象;如果不是null,那么就直接返回value不是null的Optional对象 // 可以看到这里和上面是有区别的。这里已经对null做过了处理,那么在使用的时候,如果value不是null的时候,就一定返回的是value不是null的Optional对象 public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); } // 如果值为null,那么就直接抛出异常;如果不为null,就直接返回这个value。 public T get() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; } // 如果value不是null,那么就直接返回true;如果value是null,那么就直接返回false; public boolean isPresent() { return value != null; } // 如果value不为null,那么就可以对这个value值来进行操作了 // 如果为null,那么就什么都不做 public void ifPresent(Consumer<? super T> consumer) { if (value != null) consumer.accept(value); } // 过滤方法。看看如何来进行实现的。 // 首先判断predicate对象不能够是空的,如果是空的就直接抛出空指针异常 // 然后在判断这个是否有,可以看到,如果value为null,那么直接返回这个value为空的对象 // 如果value不为null的时候,然后进行下一步操作。如果value符合自定义的predicate,那么就直接返回这个value的实例对象;不然就返回的是value=null的实例 // 对象 public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); } // 如果说这样的对象不为null,那么就执行下面的步骤 // 如果当前对象的value为null,那么将会返回value为null的实例对象;如果不为null,那么就会按照mapper中的方法将值来进行转换。 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)); } } // 这个比较简单了。自定义实现。如果value是空,那么就根据传进来的值作为value public T orElse(T other) { return value != null ? value : other; } // 这个也是比较容易来理解的。如果value不为null,那么就直接返回;如果value为null,那么就自己来定义一个值赋值给value 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(); } } /** * Indicates whether some other object is "equal to" this Optional. The * other object is considered equal if: * <ul> * <li>it is also an {@code Optional} and; * <li>both instances have no value present or; * <li>the present values are "equal to" each other via {@code equals()}. * </ul> * * @param obj an object to be tested for equality * @return {code true} if the other object is "equal to" this object * otherwise {@code false} */ @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); } /** * Returns the hash code value of the present value, if any, or 0 (zero) if * no value is present. * * @return hash code value of the present value or 0 if no value is present */ @Override public int hashCode() { return Objects.hashCode(value); } /** * Returns a non-empty string representation of this Optional suitable for * debugging. The exact presentation format is unspecified and may vary * between implementations and versions. * * @implSpec If a value is present the result must include its string * representation in the result. Empty and present Optionals must be * unambiguously differentiable. * * @return the string representation of this instance */ @Override public String toString() { return value != null ? String.format("Optional[%s]", value) : "Optional.empty"; } }
对上面的方法做了一个总结:可以发现上面的方法总体来说都是:对值是否是null来做了处理,防止出现空指针异常。
如果是null的话,可以实现怎样的操作;如果不是null的话,又可以做怎样的操作;以及对值可能为null的处理方式
构造方法中可以看到构造都被私有化了,只有本类中的其他的非private修饰的才能够来创建实例化对象。
对于空参构造来说,创造出来的对象的value属性为null;对于有参构造来说,value值不为null;
所以总结来说,是创建出来的对象不为null,value值可能是null,也可以不是null;具体的得看是哪个方法来进行调用的。
对于这个Optional类来说,加载类的时候就已经有了一个默认的EMPTY对象,value是为null的。
下面介绍一下方法怎么来进行使用。
要是想获取得到Optional的对象,可以通过上面的构造方法发现,外部是无法直接new对象的。那么无法直接进行new对象,那么就只能够通过其他方法来创建出来对象。如何来获取得到对象呢?那么可以看到上面方法中提供了几个静态方法:
empty(); of(T value); ofNullable(T value);
第一个方法肯定是不会来进行调用的,因为获取得到一个Optional类的value属性值为null不然符合我们的预期。
那么使用的时候就只可能是of(T value)和ofNullable(T value)这个函数了。
可以看到这两个函数很类似,但是有区别:如果使用了of(T value),可能会有两种情况,一种情况是value不为null的时候,一种情况是抛出空指针异常的情况;
对于ofNullable(T value)来说,一种情况是value为null,直接返回空实例对象,value为null;另外一种就是返回一个Optional实例对象,value不为null。
所以在选择使用的时候,看情况来进行使用。
那么对于非static关键字修饰的方法,就只有在获取得到Optional对象之后才可以来进行操作。其实获取得到对象之后,还是对对象的value值来进行操作的。
所以可以使用这个Optional对象来调用方法对value值来进行操作。如果value是空的话,如何来进行处理;如果value值不为空,那么又将会如何来进行处理。
// 如果value不是null,那么就直接返回true;如果value是null,那么就直接返回false; public boolean isPresent() { return value != null; } // 如果value不为null,那么就可以对这个value值来进行操作了 // 如果为null,那么就什么都不做 public void ifPresent(Consumer<? super T> consumer) { if (value != null) consumer.accept(value); } // value不为null的时候,就将值获取出来 public T get() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; }
所以这里一般来说最常用的就是Optional.ofNullable().ifPresent();
然后再来一个比较常用的:
Optional<User> optional = userRepository.selectOne(entity); // 如果optional不为null,那么返回ok;否则返回后面的错误码。 return optional.map(ResponseResult::getOk).orElseGet(() -> ResponseResult.getError("账号/密码错误"));
还有一个对参数校验的
String str = null; Optional.ofNullable(str).orElseThrow(()-> new RuntimeException("str为空"));