Optional方法解释以及使用

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为空"));
上一篇:Pandas和numpy如何显示全部数据


下一篇:Python - typing 模块 —— Optional