java8---Optional容器

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tangyaya8/article/details/82884543

背景:

1965年,英国一位名为Tony Hoare的计算机科学家在设计ALGOL W语言时候提出了null引用的想法,ALGOL W是第一批在堆上分配记录类型的语言之一,Hoare选择用null这种代替空引用,其理由是简单,但是后来的很多语言都采用了类似的设计方式,比如我们熟悉的Java,但是这种方式在开发中为我们带来了巨大的麻烦,我们几乎无时不刻要判断某个对象是否为空,然后才能对其做一些其他的操作。

常规操作:

例子

新建三个类:分别是Person,Car,Insurance,他们的关系是依赖
Insurance依赖Car依赖Person

Insurance:

package com.tangbaobao.java8.option;

import lombok.Getter;

/**
 * @author tangxuejun
 * @version 2018/9/28 10:13 AM
 */
@Getter
public class Insurance {
    private String InsuranceName;
    private double price;
}

Car:

package com.tangbaobao.java8.option;

import lombok.Getter;

/**
 * @author tangxuejun
 * @version 2018/9/28 10:12 AM
 */
@Getter
public class Car {
	private String carName;
    private Insurance insurance;
}

Person:

package com.tangbaobao.java8.option;

import lombok.Getter;

import java.util.Optional;

/**
 * @author tangxuejun
 * @version 2018/9/28 10:12 AM
 */
@Getter
public class Person {
	private name;
    private Car car;
}

出现NullPointException

public class {
public static void main(String ...){
		Person p;
		System.out.println(p.getCar());
	}
}

这是因为调用了一个未在堆上分配内存空间的空引用,即person 为null

解决办法:

通常我们在拿取形参的时候都会判断这个参数是否不为null,类似这样:

public void displayPerson(Person person){
	if(person !=null){
		System.out.println(person);
	}
}

**如果是要调用最底层的类型,则要判断很多层,类似这样:

public void dispayInsuranceName(Person person){
	if(person !=null){
		if(person.getCar !=null){
			if(person.getCar.getInsurance()!=null){
				System.out.println(person.getCar.getInsurance().getInsuranceName());
			}
		}
	}
}

如果对象很多层是不是看着很挫?

Optional操作:

汲取了其他语言对null的处理,在java8中引入了java.util.Optional<T>类来对对象做一些简单的封装,Optional会将对象包进去,如果对象为空则用Optional提供的静态方法Optional.empty();返回一个空的Optional对象;

重构Person,Car,Insurance类

Insurance:

package com.tangbaobao.java8.option;

import lombok.Getter;

/**
 * @author tangxuejun
 * @version 2018/9/28 10:13 AM
 */
@Getter
public class Insurance {
	//对于Insurance来说,它的名称和价格都不应该不存在,所以不用Optional容器来包装
    private String InsuranceName;
    private double price;
}

Car:

package com.tangbaobao.java8.option;

import lombok.Getter;

/**
 * @author tangxuejun
 * @version 2018/9/28 10:12 AM
 */
@Getter
public class Car {
	private String carName;
	//汽车可能没有保险,所以用Optional容器来包装
    private Optional<Insurance> insurance;
}

Person:

package com.tangbaobao.java8.option;

import lombok.Getter;

import java.util.Optional;

/**
 * @author tangxuejun
 * @version 2018/9/28 10:12 AM
 */
@Getter
public class Person {
	private name;
	//人可能没有汽车,所以也用Optional容器来包装
    private Optional<Car> car;
}

重构获取保险名称的代码

在Option类中同样提供了map(Function)方法来对Optional容器做一些操作:

//获取Car
Optional<Person> person = Optional.empty();
Optional<Optional<Car>> car = person.map(Person::getCar);
//获取保险名称
Optional<Insurance> insurance = Optional.empty();
Optional<String> s = insurance.map(Insurance::getInsuranceName);

如上所示,可以用map方法获取Optional中的对象,但是获取的对象还是为Optional类型,所以要将上一层的Optiona去除,这时我们要用到流的扁平化中用到的flatMap,它可以将多个流中扁平化达到我们的效果;

Optional<Person> person = Optional.empty();
Optional<String> insuraceName = person.flatMap(Person::getCar)
        .flatMap(Car::getInsurance)
        .map(Insurance::getInsuranceName);

如果Person,Car,Insurance中的一个为空,都会返回一个空的Optional对象,不会报空指针异常,这样是不是很优雅了呢?

两个Optional对象组合:

public Insurance findChecpestInsurance(Optional<Car> car,Optional<Person> person){
	if(car.isPresent()&&person.isPresent()){
		return dosomething(p.get(),car.get());
	}
	return Optional.empty();
}
private Insurance dosomething(Person p, Car c) {
        return null;
}

以上的代码是不是很像判断null一样呢?接下来给出更加优雅的写法:

 public Optional<Insurance> findChecpestInsurance(Optional<Person> person, Optional<Car> car) {
        return person.flatMap(p -> car.map(c -> dosomething(p, c)));
    }
    private Insurance dosomething(Person p, Car c) {
        return null;
    }

如果其中一个为空,都不会往下执行;

Optional特性:

操作了map和flatMap()是不是觉得和Stream有些类似?的确,你可以将Optional理解为最多含有一个元素的Stream。
它还提供了过滤一些元素的方法:

//过滤名称为人寿保险的公司
    public void filterByName() {
        Optional<Insurance> insurance = Optional.of(new Insurance());
        Optional<String> name = insurance
                .filter(x -> x.getInsuranceName().equals("人寿保险"))
                .map(Insurance::getInsuranceName);
    }

猜你喜欢

转载自blog.csdn.net/tangyaya8/article/details/82884543