Java8新特性【Optional详解】

177 阅读5分钟

1、简介

NullPointException应该算是企业开发中最最常见的异常,如同魔咒一般,代码中一不小心就报一个空指针异常,从而迫使程序员在敲出的每一行代码的时候都需要去思考下是否需要去做一下判空操作,久而久之,代码中便充斥着大量的 null 检查逻辑。

public void getCompanyFromEmployee() {\
    Employee employee = getEmployee();\
    if (employee == null) {\
        // do something here...\
        return;\
    }\
    Team team = employee.getTeam();\
    if (team == null) {\
        // do something here...\
        return;\
    }\
    Department department = team.getDepartment();\
    if (department == null) {\
        // do something here...\
        return;\
    }\
    Company company = department.getCompany();\
    System.out.println(company);\
}

Optional 类是 Java 8 引入的一个很有趣的特性。Optional 类主要解决的问题是臭名昭著的空指针异常(NullPointerException) 。本质上,这是一个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空。

2、Optional中方法说明

方法名描述
static Optional empty()返回空的 Optional 实例。
Optional filter(Predicate<? super predicate)如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。
Optional map(Function<? super T,? extends U> mapper)如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。
Optional flatMap(Function<? super T,Optional> mapper)如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional
T get()如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException
boolean isPresent()如果值存在则方法会返回true,否则返回 false。
void ifPresent(Consumer<? super T> consumer)如果值存在则使用该值调用 consumer , 否则不做任何事情。
static Optional of(T value)返回一个指定非null值的Optional,传NULL报空指针异常。
static Optional ofNullable(T value)如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。
T orElse(T other)如果存在该值,返回值, 否则返回 other。
T orElseGet(Supplier<? extends T> other)如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。
T orElseThrow(Supplier<? extends X> exceptionSupplier)如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常

3、Optional方法使用

3.1、Optional对象创建

// 1、创建一个包装对象值为空的Optional对象
Optional<String> optEmpty = Optional.empty();
// 2、创建包装对象值非空的Optional对象,如果传递的参数是 null,抛出异常 NullPointerException
Optional<String> optOf = Optional.of("optional");
// 3、创建包装对象值允许为空也可以不为空的Optional对象
Optional<String> optOfNullable1 = Optional.ofNullable(null);
Optional<String> optOfNullable2 = Optional.ofNullable("optional");

3.2、Optional.get()方法(返回对象的值)

//返回对象的值,如果为空则抛出异常 “No value present”
Person person=new Person();
person.setAge(2);
Optional.ofNullable(person).get();

3.3、Optional.isPresent()方法(判读是否为空)

无参方法:

//会返回一个boolean类型值,如果对象不为空则为真,如果为空则false
 Person person=new Person();
    person.setAge(2);
    if (Optional.ofNullable(person).isPresent()){
    //写不为空的逻辑
    System.out.println("不为空");
    }else{
     //写为空的逻辑
     System.out.println("为空");
    }

有参方法:

//如果对象非空,则运行函数体
Person person=new Person();
person.setAge(2);
Optional.ofNullable(person).ifPresent(p -> System.out.println("年龄"+p.getAge()));

3.4、Optional.filter()方法(过滤对象)

filter()方法大致意思是,接受一个对象,然后对他进行条件过滤,如果条件符合则返回Optional对象本身,如果不符合则返回空Optional。

        Person person=new Person();
        person.setAge(2);
        Optional.ofNullable(person).filter(p -> p.getAge()>50);

3.5、Optional.map()、flatMap()方法(对象进行二次包装)

map()方法: map()方法将对应Funcation函数式接口中的对象,进行二次运算,封装成新的对象然后返回在Optional中。

Person person1=new Person();
person.setAge(2);
String optName = Optional.ofNullable(person).map(p -> person.getName()).orElse("name为空");

flatMap()方法: flatMap()方法将对应Funcation函数式接口中的对象,进行二次运算,封装成新的Optional对象然后返回在Optional中。

List<String> strings1 = Optional.ofNullable(personList).flatMap(list -> {
			List<String> result = new ArrayList<>();
			list.stream().forEach(person -> {
				result.add(person.getName());
			});
			return Optional.ofNullable(result);
		}).orElse(null);

map()和flatMap()区别: 先看这两个方法的源码:

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

结论:map的返回值Optional对象是在map方法里面自动封装好了。而flatMap方法是自己的实现的逻辑中自己封装。

3.6、Optional.orElse()方法(为空返回对象)

//常用方法之一,这个方法意思是如果包装对象为空的话,就执行orElse方法里的value,如果非空,则返回写入对象
Person person1=new Person();
person.setAge(2);
Optional.ofNullable(person).orElse(new Person("小明", 2));

3.7、Optional.orElseGet()方法(为空返回Supplier对象)

//这个与orElse很相似,入参不一样,入参为Supplier对象,为空返回传入对象的.get()方法,如果非空则返回当前对象
Optional<Supplier<Person>> sup=Optional.ofNullable(Person::new);
//调用get()方法,此时才会调用对象的构造方法,即获得到真正对象
 Optional.ofNullable(person).orElseGet(sup.get());

3.8、Optional.orElseThrow()方法(为空返回异常)

这个我个人在实战中也经常用到这个方法,方法作用的话就是如果为空,就抛出你定义的异常,如果不为空返回当前对象,在实战中所有异常肯定是要处理好的,为了代码的可读性。

//简单的一个查询
        Member member = memberService.selectByPhone(request.getPhone());
        Optional.ofNullable(member).orElseThrow(() -> new ServiceException("没有查询的相关数据"));

4、JDK9对Optional优化

增加了三个方法:or()、ifPresentOrElse() 和 stream()

or() 与orElse等方法相似,如果对象不为空返回对象,如果为空则返回or()方法中预设的值。ifPresentOrElse() 方法有两个参数:一个 Consumer 和一个 Runnable。如果对象不为空,会执行 Consumer 的动作,否则运行 Runnable。相比ifPresent()多了OrElse判断。stream()将Optional转换成stream,如果有值就返回包含值的stream,如果没值,就返回空的stream。