1. ホーム
  2. Java

JDK8 の Optional.of と Optional.ofNullable メソッドの違いと使い方を説明する。

2022-02-13 16:53:58

作者がNPEを報告するために使ったので、特に言うことはないです。

普段はOptionalを使ってデフォルト値を設定し、NULLを排除しています。しかし、最近Optional.ofを使ってNullポインタを報告しました。

では、ソースコードを見てみましょう。

    /**
     * Returns an {@code Optional} with the specified present non-null value.
     *
     * @param <T> the class of the value
     * @param value the value to be present, which must be non-null
     * @return an {@code Optional} with the value present
     * @throws NullPointerException if value is null
     */
    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

    /**
     * Constructs an instance with the value present.
     *
     * @param value the non-null value to be present
     * @throws NullPointerException if value is null
     */
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

  /**
     * Checks that the specified object reference is not {@code null}. This
     This * method is designed primarily for doing parameter validation in methods
     This * method is designed primarily for doing parameter validation in methods * and constructors, as demonstrated below:
     * <blockquote><pre>
     * public Foo(Bar bar) {
     * this.bar = Objects.requireNonNull(bar);
     * }
     * </pre></blockquote>
     *
     * @param obj the object reference to check for nullity
     * @param <T> the type of the reference
     * @return {@code obj} if not {@code null}
     * @throws NullPointerException if {@code obj} is {@code null}
     */
    public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }

メソッドを段階的にチェックすると、T 値が null の場合、Optional.of(T 値) を使用すると手動で NullPointerException() をスローすることがわかります。

ですから、このメソッドは、NULLが存在してはいけないということに、特に注意して使ってください。

では、どの方法を使えばいいのでしょう。

Optional.ofNullableです。

    /**
     * Returns an {@code Optional} describing the specified value, if non-null,
     * otherwise returns an empty {@code Optional}.
     *
     * @param <T> the class of the value
     * @param value the possibly-null value to describe
     * @return an {@code Optional} with a present value if the specified value
     * is non-null, otherwise an empty {@code Optional}
     */
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

    /**
     * Returns an empty {@code Optional} instance. no value is present for this
     * No value is present for this.
     No value is present for this * Optional.
     * @apiNote Though it may be tempting to do so, avoid testing if an object
     * is empty by comparing with {@code ==} against instances returned by
     * {@code Option.empty()}. There is no guarantee that it is a singleton.
     There is no guarantee that it is a singleton. * Instead, use {@link #isPresent()}.
     *Instead, use {@link #isPresent()}.
     * @param <T> Type of the non-existent value
     * @return an empty {@code Optional}
     */
    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

    /**
     * Common instance for {@code empty()}.
     */
    private static final Optional<? > EMPTY = new Optional<>();

    /**
     * Constructs an empty instance.
     *
     * @implNote Generally only one empty instance, {@link Optional#EMPTY},
     * should exist per VM.
     */
    private Optional() {
        this.value = null;
    }

    /*
     * Return the value if present, otherwise return {@code other}.
     *@param other
     * @param other the value to be returned if there is no value present, may
     * be null
     * @return the value, if present, otherwise {@code other}
     */
    public T orElse(T other) {
        return value ! = null ? value : other;
    }

えー、これは動作します、もしvalueがnullなら、新しいOptional()を手動で作成します;しかしthis.value = nullです。だから今回は手動でnullポインタを投げるコードのブロックからジャンプします。このとき、orElse(T other)を使えばいいのです。ソースコードを見ると、value == nullの場合はotherの値が取られるようです。