从 Java 8 引入的一个很有趣的特性是 Optional 类。Optional 类主要解决的问题是空指针异常(NullPointerException)。本质上是一个包装类,包装了可能为null的对象,并提供一下便利的工具方法。
empty()/of(T value)/ofNullable(T value) 的区别
- empty 方法生成了一个空的optional对象,该optional对象,包裹的对象为null。
- of 方法的入参必须为一个非null 的对象。若入参为null的对象,该方法将会抛出NullPointerException。因为of方法调用了Optional类的私有构造方法,而该构造方法有调用了Object类中的requireNonNull方法,requireNonNull方法在入参为null时抛出异常。
- ofNullable方法入参若为null,则返回optional内部的空对象;若入参不为null,调用of方法构造optional对象。
代码片段1:
/**
* 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 <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;
}
/**
* 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);
}
/**
* 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);
}
/**
* 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);
}
代码片段2:
public final class Objects {
......
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
......
}
orElse(T other)/orElseGet(Supplier<? extends T> other)/<X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)的区别
- 若optional所包装的对象不为null,orElse方法返回optional对象所包裹的对象;若optional对象所包裹的为null,orElse方法则返回该方法的入参。
- 若optional所包装的对象不为null,orElseGet方法返回optional对象所包裹的对象;若optional对象所包裹的为null,orElseGet方法通过入参other构造一个对象。
- 若optional所包装的对象不为null,orElseThrow方法返回optional对象所包裹的对象;若optional对象所包裹的为null,orElseThrow方法通过入参exceptionSupplier抛出一个异常。
/**
* 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();
}
/**
* Return the contained value, if present, otherwise throw an exception
* to be created by the provided supplier.
*
* @apiNote A method reference to the exception constructor with an empty
* argument list can be used as the supplier. For example,
* {@code IllegalStateException::new}
*
* @param <X> Type of the exception to be thrown
* @param exceptionSupplier The supplier which will return the exception to
* be thrown
* @return the present value
* @throws X if there is no value present
* @throws NullPointerException if no value is present and
* {@code exceptionSupplier} is null
*/
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}