Optional类的使用

简介

一个可以包含空值或不是空值的容器。如果该值存在则isPresent()返回true,调用get()返回这个值。
简而言之就是Optional是一个容器,保存T类型的值或保存null,Optional提供很多方法,这样我们就无需用显示进行空值检查。
jdk1.8后,Optional类的可以很好的解决空指针异常。

源码解析

Optional类有两个属性:

    private static final Optional<?> EMPTY = new Optional<>();

    private final T value;

EMPTY是给empty()静态方法提供的一个空的Optional对象,调用empty()方法就会返回一个空的Optional对象,若容器内对象非空,则为value该值,如果为null则value则不代表任何值。

    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

这是empty()方法,就是返回一个空的Optional<T>对象。
Optional类有两个构造方法。

    private Optional() {
        this.value = null;
    }
    
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

第一个是私有的构造方法,它就是提供一个空的实例,也没什么好说的。无非就是在上面EMPTY属性那里调用了一次,供empty()方法使用。
第二个构造方法在调用时,对于value的进行了一次非空检查,如果传入的是null,则会抛出NullPointerException,也是私有化的,主要是提供给下面两个方法使用:of(T value)ofNullable(T value)

    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }
   
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

这两个方法就是我们常用用于获取T类型的Optional<T>类型对象的方法,of(T value)方法只是调用了上面提到的Optional(T value)构造方法,所以它有可能会抛出NullPointerException异常。
ofNullable(T value)方法对value进行了一次空值检查,value == null ? empty() : of(value),当传入的valuenull的时,会调用empty()方法,将EMPTY属性返回,也就是一个空的Optional对象,而当value非空,会调用of(T value)方法,返回一个Optional<T>类型对象。这样就跳过了第二个私有化的构造方法中可能会抛出空指针异常的一步,是引入Optional<T>的很重要的优点。

继续往下看get()方法

	public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }

这个方法就是将我们调用of(T value)ofNullable(T value)这连哥哥方法传入的value返回,当value为空值时会抛出NoSuchElementException异常。所以要谨慎使用,建议确认value不为空时使用。
isPresent()方法

   public boolean isPresent() {
       return value != null;
   }

这个方法就是对value进行了一次是否为空的判断。

继续来看下面几个方法:

    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }
    
    public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
    }

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

    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表达式食用更香。
ifPresent(Consume<T> consumer方法Consumer接口,对value进行空值校验,然后消费这个数据。举个例子:

	public static void main(String[] args) {
        Optional.ofNullable("abc").ifPresent(System.out::print);
        Optional.ofNullable("a,b,c")
                .ifPresent(str -> Arrays.stream(str.split(","))
                        .map(String::toUpperCase)
                        .forEach(System.out::println));
    }

这样直观很多,传进来的"a,b,c"作为value传进来处理成数组后,转换成大写,然后打印到控制台。

filter(Predicate<? super T> predicate)方法传入的value经过非空检验后,如果值存在,返回一个Optional用以描述这个对象,否则的话返回一个空的容器。举一个小例子:

	Optional.ofNullable("AbC")
                .filter(str -> str.startsWith("A"))
                .ifPresent(System.out::println);

可以看出,filter()方法返回的是一个Optional对象。
map(Function<? super T, ? extends U> mapper)做映射后返回一个Optional对象用以描述返回值,若没有返回值则返回一个空的容器。而flatMap(Function<? super T, Optional<U>> mapper)需要自己封装返回值成为Optional去描述返回值。

	Optional<char[]> abc = Optional.ofNullable("abc")
            .map(s -> s.toCharArray());
    Optional<char[]> abc1 = Optional.ofNullable("abc")
            .flatMap(s -> Optional.of(s.toCharArray()));

其实区别也就是else后面的一个调用Optional.ofNullable(T value)而另一个只是做空值检查而已。前者比后者多一步new Optional<>(value)操作而已。

下一个方法

	public T orElse(T other) {
        return value != null ? value : other;
    }

看起来很简单是吧,就是这么简单,value为空,返回我们传入的T类型other而已,否则返回value本身。

	public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

举一个例子吧。

	public static void main(String[] args) {
		List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
        Integer integer = integers.stream().reduce(Integer::sum).orElse(get("orElse"));
        System.out.println(integer);
        Integer orElseGet = integers.stream().reduce(Integer::sum).orElseGet(() -> get("orElseGet"));
        System.out.println(orElseGet);
    }

    private static Integer get(String s) {
        System.out.println(s + "执行");
        return 1;
    }

执行这段代码会得到

	orElse执行
	15
	15

这说明了当Optional容器中的value非空时,orElse(T other)方法需要我们传入的get(String s)方法的返回值,所以这个方法被执行了,而另一个orElseGet(Supplier<? extends T> other)并没有这种需求,所以直接返回value就结束了,并没有执行get(String s)方法。
我们再看一个例子

	public static void main(String[] args) {
        ArrayList<Integer> integers1 = new ArrayList<>();
        Integer orElse = integers1.stream().reduce(Integer::sum).orElse(get("orElse"));
        Integer orElseGet1 = integers1.stream().reduce(Integer::sum).orElseGet(() -> get("orElseGet"));
        System.out.println(orElse);
        System.out.println(orElseGet1);
    }

    private static Integer get(String s) {
        System.out.println(s + "执行");
        return 1;
    }

执行结果

	orElse执行
	orElseGet执行
	1
	1

说明当value为空的时候,两个方法都执行了。因为在方法里一个直接返回get(String s)的值,另一个是通过调用函数式接口返回的值都执行了。

下一个方法

    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }

这个方法是value存在返回值,否则抛出由 Supplier 继承的异常。比如这样使用:

	Integer integer1 = integers1.stream().reduce(Integer::sum).orElseThrow(NullPointerException::new);
	System.out.println(integer1);

结语

其实仔细看里面的方法都不难,但用好Optional能很好的解决空指针异常,所以今天就到这里了。
如果你发现我的文章哪里有错误或者有什么好的想法可以联系我,我们一起学习共同进步,我的邮箱地址是lishuangCHN@gmail.com

let’s do more of those!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值