JDK8新特性Optional

大纲

JDK8新特性Optional

Optional的出现

  我们看看在没有Optional这个类之前针对对象的判空操作:

/**
 * 传统判空
 */

@Test
public void traditionEmpty01(){
    //        String username = "蔡瑁,张允";
    String username = null;
    // 按逗号切割
    if(username != null){
        String[] split = username.split(",");
        System.out.println(Arrays.toString(split));
    }else{
        System.out.println("username is null");
    }
}

/**
 * 传统遍历集合 判空
 */

@Test
public void traditionEmpty02(){
    List<String> names = Arrays.asList("曹仁""文丑""陆逊");
    // 遍历集合前需要我们进行集合的判空,需要写一个if 比较麻烦
    if(names != null || !names.isEmpty()){
        for (String name : names) {
            System.out.println(name);
        }
    }
}

  很明显我们看到了if…else…,这样看起来就比较臃肿。

  在平时写代码中,我们需要尽量少一些if等语句的嵌套。我们的大脑不像计算机能够记住这么多条件,每次嵌套就类似与我们需要在大脑里维护一个栈,代码阅读难度变高了。

  之前安卓的同事和我说他用的Kotlin,判空比Java优雅。现在JDK8新出一个Optional类就是一个优雅判空的产生的。

Optional类的简单介绍

  JDK8的Optional类是借鉴了谷歌的工具包guava的同名Optional,它们基本上相同,是为了优雅判空,防止出现NPE空指针异常。

  使用Optional方法针对上面的第一个例子做优化,来看看是否是优雅一些。

/**
 * 使用Optional优化第一个例子的传统判空
 */

@Test
public void optimizeTraditionEmpty() {
    //        String username = "蔡瑁,张允";
    String username = null;
    Optional.ofNullable(username).ifPresent(name -> {
        String[] split = username.split(",");
        System.out.println(Arrays.toString(split));
    });
}

  就算上面的username为空,也不会抛出空指针NPE异常。

Optional的创建

  Optional类的构造方法都是私有的,我们无法通过new来创建Optional对象,只能通过它提供的API来创建该对象。通常有下面三种方式创建

  • empty() :创建一个空的Optional实例
  • of(T value) :创建一个封装了T对象的Optional实例
  • ofNullable(T value) :创建一个封装了T对象的Optional实例

在Optional类中有一个重要的成员变量value,这个变量就是被封装的对象。

还有一个表示空的Optional的EMPTY。

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

private final T value;

看下创建方法的源码:

// 很明显 直接拿EMPTY进行类型转换
public static<T> Optional<T> empty() {
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}

// 调用私有构造方法创建一个Optional对象,value为null时会抛出空指针异常
public static <T> Optional<T> of(T value) {
    return new Optional<>(value);
}

// 传入的值为null时,创建空的Optional对象
// 不为空就创建封装指定值的Optional对象
// 这个最常用
public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}

Optional的其他方法

get方法

  显而易见,get方法就是直接获取Optional对象封装的对象,假如为null是会抛出找不到元素异常。

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

isPresent方法

  该方法是判断Optional封装的对象是否是空。

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

  为了演示该方法的用法,下面写一个例子,但是在实际编写代码的时候是不推荐这么写的。

@Test
public void isPresentDemo(){
    String username = "lv meng"// 吕蒙
    Optional<String> op = Optional.ofNullable(username);
    if(op.isPresent()){
        String upperUsername = op.get().toUpperCase();
        System.out.println(upperUsername);
    }else{
        System.out.println("username is null");
    }
}

  我们虽然使用了isPresent方法,但是它返回的还是布尔值,所以还是需要if判断,那Optional就失去意义了,所以一般不使用isPresent方法,有更好的方法来优化这个问题。

ifPresent方法

  推荐使用ifPresent方法,假如Optional封装的值是null,则不做任务处理,很好的规避了NPE异常。需要我们传递一个消费者Consumer接口,做我们要做的处理就好了。

public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}

  我们使用ifPresent方法来优化上面这个例子:

@Test
public void ifPresentDemo(){
    String username = "lv meng"// 吕蒙
    Optional<String> op = Optional.ofNullable(username);
    op.ifPresent(name ->{
        System.out.println(name.toUpperCase());
    });
}

filter方法

  通过传入一个Predicate函数来对Optional封装的值进行过滤操作。假如满足过滤条件就返回当前Optional对象,不满足就返回一个空的Optional对象,也就是 empty()。

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

  判断某个数组长度是否大于3:

@Test
public void filterDemo(){
    // 判断集合的长度是否大于3
    List<String> nameList = Arrays.asList("关平""徐庶""诸葛村夫""王司徒");
    Optional optional = Optional.ofNullable(nameList).filter(names ->
     names.size() > 3
    );

    System.out.println(optional);
}

map方法

  map方法是一个转换方法,可以将一个类型转换成另一个类型,这是通过Function完成的。

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

  例子:将某个字符串转换成它的长度。

@Test
public void mapDemo(){
    String username = "康帅博蜂蜜柚子";
    Optional<Integer> op = Optional.ofNullable(username).map(name ->
     name.length()
    );
    System.out.println(op);
}

flatMap方法

  flatMap方法和map方法其实差不多,只不过Function函数里的apply方法的返回值类型是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));
    }
}

  例子:将某个字符串转换成它的长度。

@Test
public void flatMapDemo(){
    String username = "康帅博脑残牛肉面";
    Optional<Integer> op = Optional.ofNullable(username).flatMap(name ->
  Optional.ofNullable(name.length())
    );
    System.out.println(op);
}

orElse方法

  orElse方法就是当Optional封装的值为null时,返回orElse传入的值作为替代。

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

  例子:

@Test
public void orElseDemo(){
    String username = null;
    username = Optional.ofNullable(username).orElse("unkown name");
    System.out.println(username);
}

orElseGet方法

  该方法和orElse方法的区别是orElse方法是直接传入指定值的,而orElseGet需要传递一个生产接口。

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

  例子:

@Test
public void orElseGetDemo(){
    String username = null;
    username = Optional.ofNullable(username).orElseGet(()->{
        String name = "東南西北中發";
        return name.substring(4);
    });
    System.out.println(username); // 中發
}

orElseThrow方法

  orElseThrow方法直接在生产接口Supplier创建一个异常对象就可以了,当Optional封装的对象的值是null时,直接抛出我们预先准备的异常。

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

  例子:

@Test
public void orElseThrowDemo(){
    String username = null;
    username = Optional.ofNullable(username).orElseThrow(()->
     new RuntimeException("username is null")
    );
    System.out.println(username);
}

小结

  Optional是有一个可以为null的容器对象,正确使用Optional对象可以有效的避免空指针NPE异常,写出优雅的代码。

  谨慎使用get方法,不要用isPresent的方法。Optional对象最重要的方法就是ifPresent方法了,多用几次就熟悉了。


JDK8新特性Optional


原文始发于微信公众号(肝帝笔记):JDK8新特性Optional

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/31535.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!