Optional类
隶属于java.util包中
简而言之,这个类的出现,相当于Java8提供了一个封装好的容器,在使用的时候可以放心大胆的处理null的逻辑或异常。需要把值放入容器中,后续的取值操作和其他逻辑,使用其提供的Api即可方便简单的处理null指针的情况。
Optional类的源码数量并不多,有时间还是可以看看的,先看看3个初始化容器内容的静态方法,(empty,of,ofNullable),由于所有构造函数都是private的,所以只能使用工厂方法来获取Optional的实例
在类中第一行便是定义了一个静态常量EMPTY,泛型的使用的是通配符?,意思是可以传入任意类型,并赋值为空参构造实例,第二行定义为final的value,则是用于存储放入容器中的值
/**
* Common instance for {@code empty()}.
*/
private static final Optional<?> EMPTY = new Optional<>();
/**
* If non-null, the value; if null, indicates no value is present
*/
private final T value;
private Optional() {
this.value = null;
}
复制代码
静态方法empty
这个方法作用很简单,就是将类加载时初始化的EMPTY静态常量强转成传入的泛型T,然后返回强转后的值,可以调用该方法返回一个值为null的Optional容器
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
复制代码
使用方式,声明一个value类型为String的空容器
Optional<String> empty = Optional.empty();
复制代码
静态方法of
这个方法相当于要求传入一个值,该值会做为容器中的值,调用顺序是传入值后,调用Optional的构造方法,而构造方法会调用Objects.requireNonNull方法去判断传入的值是否为空,如果为空则直接抛出空指针异常NullPointerException,不为空则返回值并赋值给成员属性value
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
复制代码
构造函数中调用的Objects类的requireNonNull方法
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
复制代码
使用方式,声明一个容器,并且值为123,通过实例方法get可以获取出使用of方法初始化的值
Optional<Integer> a = Optional.of(123);
Integer integer = a.get();
复制代码
静态方法ofNullable
这个方法逻辑比较简单,判断传入的值是否为空,为空则调用上面说的empty方法,不为空则调用上面说的of方法
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
复制代码
下面看看一些实例方法是怎么实现的
get方法
在of方法中演示过用法了,其作用就是返回当前容器中value的值,如果为value为空则直接抛出NoSuchElementException异常
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
复制代码
isPresent方法
判断当前容器中value的值是否为空,并返回一个boolean值
public boolean isPresent() {
return value != null;
}
复制代码
使用:先判断值是否为空,如果为空直接调用get方法会报错
if (optional.isPresent()) {
p = optional.get();
}
复制代码
ifPresent方法
判断当前容器中value的值是否为空,空则什么都不做,不为空则将value传入Consumer的accept中执行
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
复制代码
java.util.function.Consumer是JDK提供的函数接口,包含了一个无返回值的带参的方法: void accept(T t),传入一个泛型类型的参数并执行一些操作。 由于这是一个函数式接口,可以使用传统的匿名内部类编写,也可以使用Lambda表达式,函数接口和Lambda表达式在这里不再赘述
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
复制代码
使用:分别采取了匿名内部类和lambda表达式的方式编写,由于value不为null,所以都会执行accept方法并输出test字符串
Optional<String> data = Optional.of("test");
data.ifPresent(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
data.ifPresent(System.out::println);
复制代码
orElse方法
判断当前容器中value的值是否为空,不为空则返回value,空则返回传入的值
public T orElse(T other) {
return value != null ? value : other;
}
复制代码
使用:由于容器中的值为空,所以会返回test字符串
Optional<String> empty = Optional.empty();
System.out.println(empty.orElse("test"));
复制代码
orElseGet方法
判断当前容器中value的值是否为空,不为空则返回value,空则调用Supplier实例的get方法,<? extends T>的作用为返回值类型只能是T类型或T的子类型
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
复制代码
java.util.function.Supplier是JDK提供的函数接口,包含了一个无参的方法: T get(), 用来返回一个泛型参数指定类型的对象
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
复制代码
使用:分别采取了匿名内部类和lambda表达式的方式编写,由于value的值为null,所以最终返回值都是Supplier实例的get方法返回值
Optional<String> empty = Optional.empty();
String anonymity = empty.orElseGet(new Supplier<String>() {
@Override
public String get() {
return "anonymity";
}
});
String lambda = empty.orElseGet(() -> "lambda");
System.out.println(anonymity);
System.out.println(lambda);
// 输出两行字符串,"anonymity"和"lambda"
复制代码
orElseThrow方法
和orElseGet类似,泛型函数的泛型<X extends Throwable>作用为返回值类型只能是Throwable类型或Throwable的子类型,如果值为空,则直接抛出一个异常
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
复制代码
使用:分别采取了匿名内部类和lambda表达式的方式编写,由于value的值为null,所以最终返回值都是Supplier实例的get方法返回值,可以直接往上抛异常或者try catch捕获处理,这段代码执行后便会抛出任意一个异常
public static void main(String[] args) throws Exception {
Optional<Object> empty = Optional.empty();
// 这段注释掉则抛出后面的lambda表达式返回的异常
empty.orElseThrow(new Supplier<Exception>() {
@Override
public IllegalArgumentException get() {
return new IllegalArgumentException("value is null,from anonymity");
}
});
// 这段注释掉则抛出匿名内部类返回的异常
empty.orElseThrow((Supplier<Exception>) () -> new IllegalArgumentException("value is null,from lambda"));
}
复制代码
map方法
首先判断参数mapper是否为空,空则抛出空指针异常,再判断当前容器中value的值是否为空,空则调用empty方法,不为空则返回ofNullable方法的返回值,ofNullable的参数为mapper的返回值,mapper类型为Function类型,和上面讲过的Supplier类似,作用就是如果值不为空,可以执行一个函数进行二次逻辑数据处理并返回。这个mapper函数有两个泛型T和U,T是定义在Optional类名上的,public后面紧跟的<U>作用是声明这个方法有一个泛型U(声明为泛型方法),Function的泛型参数则限定了第一个参数为T类型或T的父类型,第二个参数为U类型或U的子类型
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));
}
}
复制代码
java.util.function.Function是JDK提供的函数接口,方法applay的作用就是传入一个值,返回另一个值
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
}
复制代码
使用:分别采取了匿名内部类和lambda表达式的方式编写,由于value的值不为空,两个变量接受的Optional实例中的值都为3
Optional<String> data = Optional.of("test");
Optional<Integer> integer = data.map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return s.length() > 3 ? 1 : 0;
}
});
Optional<Integer> integer2 = data.map(s -> s.length() > 3 ? 1 : 0);
System.out.println(integer.get());
System.out.println(integer2.get());
// 输出两行字符串3
复制代码
flatMap方法
首先判断参数mapper是否为空,空则抛出空指针异常,再判断当前容器中value的值是否为空,空则调用empty方法,不为空则调用Objects.requireNonNull函数的返回值,将mapper.apply返回值传入,如果apply方法的返回值为空则会抛出异常,使用的方法与map非常类似,唯一区别是map返回值会被调用ofNullable方法进行容器包装,而flatMap要求直接返回Optional容器
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));
}
}
复制代码
使用:分别采取了匿名内部类和lambda表达式的方式编写,使用匿名内部类编写的applay方法返回了一个值为数字1的容器,可调用get输出,使用lambda表达式编写的因为执行Objects.requireNonNull(null)所以抛出异常
Optional<String> data = Optional.of("test");
Optional<Integer> integer = data.flatMap(new Function<String, Optional<Integer>>() {
@Override
public Optional<Integer> apply(String s) {
return Optional.of(1);
}
});
System.out.println(integer.get());
// 输出两行字符串3
data.flatMap(s -> null);
// 执行到这里就会抛出异常,因为调用了Objects.requireNonNull(null)
复制代码
filter方法
首先判断参数predicate是否为空,空则抛出空指针异常,再判断当前容器中value的值是否为空,空则返回当前实例,不为空则返回一个三元表达式,会将当前容器的值传入predicate.test函数中,返回一个boolean值,如果true则返回当前实例,否则调用empty函数返回一个空容器,作用就是过滤筛选值。Predicate也是一个函数接口。
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
复制代码
java.util.function.Predicate是JDK提供的函数接口,方法test的作用就是传入一个值,返回一个boolean值
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
}
复制代码
使用:分别采取了匿名内部类和lambda表达式的方式编写,由于rightly的value值不为空,会输出test,而falsely.get()则会抛出异常
Optional<String> data = Optional.of("test");
Optional<String> rightly = data.filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.equals("test");
}
});
Optional<String> falsely = data.filter(s -> s.equals(""));
System.out.println(rightly.get());
System.out.println(falsely.get());
// 会先输出一次"test"
// 然后falsely.get时就会抛出异常,因为value为null
复制代码
至此,Optional类中所有的方法和逻辑都阅读完了,源码清晰简单,阅读一遍明白其中的逻辑,对该工具类的使用会有一定的帮助。:)
原文链接:juejin.cn/post/7051827225515163661










