Java8之Optional

ぐ巨炮叔叔 提交于 2020-01-12 15:08:11

Optional类是为了避免空指针异常的发生
其中有三种创建Optional实例的方法,我们接下来进行分别介绍

第一种方法 ---- empty (静态方法)

源码:

 // 静态方法,可以使用类名直接使用。
 // 返回一个空的Optional实例。
 public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

示例代码:

Optional<String> optional = Optional.empty();
第二种方法 ---- of (静态方法)

源码:

// 
public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

示例代码:

// 直接定义值,返回一个值不为空的Optional示例
Optional<String> optionalS = Optional.of("hello");
第三种方法 ---- ofNullable(静态方法)

源码:

// 根据源码分析,这个方法跟of方法差不多,只是在判断了设置的值是否为null,
// 如果为null,返回空的Optional示例;否则,调用of方法,创建实例。
public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}

示例代码:

// 当不知道对象是否是null的时候,使用该方法
// 如果为null,返回空的Optional示例;否则,调用of方法,创建实例。
Optional<String> optionalS = Optional.ofNullable("hello");

前面讲了如何构造出Optional实例对象,接下来,就继续看看怎么取得Optional里面的值。

public boolean isPresent() {
        return value != null;
    }
// 如代码所示,使用get方法,就可以拿到值。
// 但是注意一点,首先第一行有一个判断,那么这个方法是干什么的呢。
// 上面的源码就是isPresent方法,直接就判断值是否为null。
if (optionalS.isPresent()) {
    System.out.println(optional.get());
}

上面这种写法,跟下面的这个写法是没有任何区别的,所以是不推荐上面这种写法的。

if (null != optionalS) {
    System.out.println(optionalS.get());
}

推荐的Optional使用方式

// 参数是consumer,消费者类型。如果值不为null,调用消费者返回值。
// 关于消费者类型接口下一篇会进行讲解
public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }
// 根据上面的源码分析,ifPresent方法会帮我们判断值是否为null;
// 如果不为null,返回值
optional.ifPresent(item -> System.out.println(item));

上面才是推荐的Optional使用的方式,但是这个时候也有一个小的技巧,当optional值为null时,他会返回null,但是大多是的时候,我们应该给前台返回一个空的list。这样前台在遍历list的时候,也就不会报错了。

// 判断值是否为null,返回相应的返回值
public T orElse(T other) {
    return value != null ? value : other;
}
// 接收一个supplier接口类型的参数(供应商接口,不接收参数返回一个值,前面讲过),
 public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }
// 下面这两种方法都是可以在optional为null时,返回相对应的自己设置的值
System.out.println(optionalS.orElse("world"));
System.out.println(optionalS.orElseGet(() -> "nihao"));

那么这两个方法有什么区别吗?
当然有区别了。
示例代码:

// 当optional实例有值的情况下,orElse方法还是会执行test方法;而orElseGet则不会执行,到此结束。	
Optional<String> optional = Optional.of("aaaa");
System.out.println("orElse方法");
optional.orElse(test1());
System.out.println("orElseGet方法");
optional.orElseGet(() -> test1());

 private static String test1() {
     System.out.println("进入方法");
     return null;
}

// 输出结果
orElse方法
进入方法
orElseGet方法
// 当optional实例的值为null的情况下,orElse方法还是会执行test方法;而orElseGet则不会执行,到此结束。
Optional<String> optional = Optional.empty();
System.out.println("orElse方法");
optional.orElse(test1());
System.out.println("orElseGet方法");
optional.orElseGet(() -> test1());

private static String test1() {
    System.out.println("进入方法");
    return null;
}

// 输出结果
orElse方法
进入方法
orElseGet方法
进入方法

上面使用的是单个实体,下面我们将使用列表来暂时怎么使用optional。

// 接收一个Function类型参数(函数式接口,接收一个值,返回一个值),返回Optional类型值。
// 这里的逻辑也很简单,判断参数
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));
    }
}
Employee employee1 = new Employee();
employee1.setName("zhangsan");

Employee employee2 = new Employee();
employee2.setName("lisi");

Company company = new Company();
company.setName("company1");

List<Employee> employees = Arrays.asList(employee1,employee2);
company.setEmployeeList(employees);

Optional<Company> optionalCompany = Optional.ofNullable(company);
// 调用map方法,判断参数是否为null,如果为null,返回orElse方法里面的值
List<Employee> employees1 = optionalCompany.map(theCompany ->
theCompany.getEmployeeList()).orElse(Collections.emptyList());
System.out.println(employees1);

上面是Optional类的正确使用方法,很好的避免了空指针的异常。
自己还没怎么使用过,边学习边使用吧。一起加油。

一个问题:

如果上述的设置List这样写company.setEmployeeList(null);

public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }

map方法再调用Objects.requireNonNull()时,为什么不抛出异常。如果你知道,请告诉我,谢谢。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!