使用Optional.of、ofNullable、orElse、orElseGet遇到的坑

of()与ofNullable()的区别

从方法名上对比理解,就是ofNullable() 可以支持null值,那of()就不支持null值。

下面看下源码:

java.util.Optional.java

    /**
     * Returns an {@code Optional} with the specified present non-null value.
     *
     * @param  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);
    }

java.util.Objects.java

    /**
     * Checks that the specified object reference is not {@code null}. This
     * method is designed primarily for doing parameter validation in methods
     * and constructors, as demonstrated below:
     * 
     * public Foo(Bar bar) {
     *     this.bar = Objects.requireNonNull(bar);
     * }
     * 
* * @param obj the object reference to check for nullity * @param 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; }

从上面的源码可以看到of()方法里面做了判空抛出NPE处理,如果不想抛出NPE,则使用ofNullable()

ofNullable()的源码


    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;
    }

    /**
     * Returns an {@code Optional} describing the specified value, if non-null,
     * otherwise returns an empty {@code Optional}.
     *
     * @param  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
     * 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.
     * Instead, use {@link #isPresent()}.
     *
     * @param  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;
    }

建议:Optional的引入就是为了解决空指针的问题,所有我们在大多数情况下 使用的是 ofNullable()方法。

orElse()与orElseGet()的区别

下面是源码

   /**
     * Return the value if present, otherwise return {@code 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;
    }

    /**
     * Return the value if present, otherwise invoke {@code other} and return
     * the result of that invocation.
     *
     * @param other a {@code Supplier} whose result is returned if no value
     * is present
     * @return the value if present otherwise the result of {@code other.get()}
     * @throws NullPointerException if value is not present and {@code other} is
     * null
     */
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

可以看出,方法入参的区别。一个是传一个值,一个是传入一个函数。(传入函数的情况,就意味则需要的时候才会调用函数,不需要时就不会调用。出入值得话 就是在调用方法之前,这个值已经是确定的了,也就说这个值已经是经过运算了),下面举例。

举例

public class MTest {
    public static void main(String[] args) {
        System.out.println("1. 三目运算===========================");
        boolean one = (Boolean.TRUE) ? a():b();
        System.out.println(one);
		//输出:
		//--a--
        //true
        //说明:根据条件的真假,只会执行a或b方法的某一个。
        System.out.println("2. orElse()===========================");
        System.out.println(Optional.ofNullable(Boolean.FALSE).orElse(b()));
        //--b--
        //false
        //说明:b()方法被执行了,将b方法的返回值true作为参数传给了orElse(true)方法,但实际并未使用true。其实按正常来说,就不应该执行b(), 那下面的orElseGet() 方法就是解决这个问题的。
        System.out.println("3. orElseGet()===========================");
        System.out.println(Optional.ofNullable(Boolean.FALSE).orElseGet(() -> b()));
        //false
        //说明:不为null时,直接打印了 Boolean.FALSE的值,根本没有去调用b()方法
        System.out.println("4. of()===========================");
        System.out.println(Optional.of(null).orElseGet(() -> b()));
        //抛出异常
    }

    public static boolean a() {
        System.out.println("--a--");
        return true;
    }
    public static boolean b() {
        System.out.println("--b--");
        return true;
    }
}

上面的输出结果是:

1. 三目运算===========================
--a--
true
2. orElse()===========================
--b--
false
3. orElseGet()===========================
false
4. of()===========================
Exception in thread "main" java.lang.NullPointerException
	at java.util.Objects.requireNonNull(Objects.java:203)
	at java.util.Optional.(Optional.java:96)
	at java.util.Optional.of(Optional.java:108)
	at com.iccboy.data.test.core.credit.service.MTest.main(MTest.java:15)

Process finished with exit code 1

从上面的例子中,建议:使用ofNullable() 避免空指针, orElse()orElseGet() 根据出入的值来判断,如果是传入的一个已知的值(变量)则可用orElse(),如果传入的是一个方法则使用orElseGet()

你可能感兴趣的:(问题,Java,后端,java)