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类的说明,但是感觉不同情况下有不同的用法,所以现在结合源码再将使用场景结合一下使用。
Optional类和泛型T是相互结合着的,表示的是Option这个箱子里面装的是T类型的value,但是这个value有可能是null,也有可能不为null
/***
可能包含也可能不包含非空值的容器对象。
如果存在值,isPresent() 将返回 true,get() 将返回该值。
提供了依赖于包含值的存在与否的其他方法,例如 orElse()(如果值不存在则返回默认值)和 ifPresent()(如果值存在则执行代码块)。
这是一个基于值的类; 在 Optional 实例上使用身份敏感操作(包括引用相等 (==)、身份哈希码或同步)可能会产生不可预测的结果,应该避免。
所以可以将这个类的实例理解成是一个对值做处理的容器
*/
public final class Optional<T> {
// Optiaonal箱子里面装的值是T类型的为null的值
private static final Optional<?> EMPTY = new Optional<>();
// Optional这个箱子装的值
private final T value;
// value为null
private Optional() {
this.value = null;
}
// 返回的是T类型的null。相当于是User user = null
// 只不过这里使用Optional类给包装着
public static<T> Optional<T> empty() {
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
// 如果传递过来的value是null,那么将会存在NPE
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
// 传入进来的value如果是null,那么将会存在NPE
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
// 如果value为null,那么返回Optional<null>;如果存在着值,那么返回Optional<value>
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
// 如果值为null,那么就直接抛出异常;如果不为null,就直接返回这个value。
// 这里说明了这里还是有可能存在着为null的可能性的
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<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为空"));