Optional类
隶属于java.util包中
Optional 类是一个可以为null的容器对象,它的出现很好的解决空指针异常。
简而言之,这个类的出现,相当于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());
// 输出字符串1
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