场景
Java核心工具库Guava介绍以及Optional和Preconditions使用进行非空和数据校验:
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/127683387
上面在讲Guava时讲过Optional,下面做具体的入门示例讲解。
构建一个关系
public class Insurance { private String name; public String getName() { return name; } } public class Car { private Insurance insurance; public Insurance getInsurance() { return insurance; } } public class Person { private Car car; public Car getCar() { return car; } }
人-购买车-车买保险的关系类如上。
如果需要获取保险的名称可能需要做多重非空校验,如果person不为空,则调用person的getCar获取car对象,
如果car不为空,获取car的保险insurance,如果保险不为空,则获取保险名称。
注:
博客:
https://blog.csdn.net/badao_liumang_qizhi
实现
1、Java 8中引入了一个新的类java.util.Optional<T>。这是一个封装Optional值的类 。
变量存在时,Optional类只是对类简单封装。变量不存在时,缺失的值会被建模成一个“空”的Optional对象,
由方法Optional.empty()返回。Optional.empty()方法是一个静态工厂方法,它返回Optional类的特定单一实例。
//一 、创建Optional 对象 //1、声明一个空的Optional Optional<Object> empty = Optional.empty(); //2、依据一个非空值创建Optional Car car = new Car(); Optional<Object> o = Optional.of(car); //3、可接受null的Optional Optional<Object> o1 = Optional.ofNullable(null);
2、使用map从Optional对象中提取和转换值
把上面新建的三个类分别修改为
public class Insurance { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } import java.util.Optional; public class Car { private Optional<Insurance> insurance; public Optional<Insurance> getInsurance() { return insurance; } public void setInsurance(Optional<Insurance> insurance) { this.insurance = insurance; } } import java.util.Optional; public class Person { private Optional<Car> car; public Optional<Car> getCar() { return car; } public void setCar(Optional<Car> car) { this.car = car; } }
这里不对保险进行修改,是因为在业务上认为保险一定是有名字,但是车不一定买保险,人不一定买车。
Optional提供了一个map方法
Insurance insurance = new Insurance(); insurance.setName("badao"); Optional<Insurance> insurance1 = Optional.ofNullable(insurance); Optional<String> name = insurance1.map(Insurance::getName); System.out.println(name.get());//badao Optional<Insurance> insurance2 = Optional.ofNullable(null); Optional<String> name2 = insurance2.map(Insurance::getName); System.out.println(name2);//Optional.empty
这里的map与流的map方法相差无几。map操作会将提供的函数应用于流的每个元素。
可以把Optional对象看成一种特殊的集合数据,它至多包含一个元素。
如果Optional包含一个值,那函数就将该值作为参数传递给map,对该值进行转换。
如果Optional为空,就什么也不做。
3、使用flatMap链接Optional对象
如果是需要链接Optional对象时需要使用flatMap,比如
Car car1 = new Car(); car1.setInsurance(Optional.of(insurance)); Person person = new Person(); person.setCar(Optional.of(car1)); Optional<Person> person1 = Optional.of(person); //处理潜在可能缺失的值时,使用Optional具有明显的优势。 // 这一次,你可以用非常容易却又普适的方法实现之前你期望的效果——不再需要使用那么多的条件分支,也不会增加代码的复杂性。 String s = person1 .flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("默认名字"); System.out.println(s);
4、操纵由Optional对象构成的Stream
比如要找出person列表中所使用的保险公司名称(不含重复项)
构造一波模拟数据
Insurance insurance1 = new Insurance(); insurance1.setName("badao"); Car car1 = new Car(); car1.setInsurance(Optional.of(insurance1)); Person person1 = new Person(); person1.setCar(Optional.of(car1)); Insurance insurance2 = null; Car car2 = new Car(); car2.setInsurance(Optional.ofNullable(insurance2)); Person person2 = new Person(); person2.setCar(Optional.of(car2)); Car car3 = null; Person person3 = new Person(); person3.setCar(Optional.ofNullable(car3)); ArrayList<Person> personArrayList = new ArrayList<Person>() { { this.add(person1); this.add(person2); this.add(person3); } };
实现
Stream<Optional<String>> optionalStream = personArrayList.stream() .map(Person::getCar) .map(car -> car.flatMap(Car::getInsurance)) .map(insurance -> insurance.map(Insurance::getName));
上面三个操作得到了一个Stream<Optional<String>>对象,这些Optional对象中的一些可能为空,因为有的人可能并没有汽车,
或者有汽车但是没有投保。使用Optional,即便是碰到了值缺失的情况,你也不需要再为这些操作是否“空安全”(null-safe)
而烦心了。然而,你现在碰到了新的问题,怎样去除那些空的Optional对象,解包出其他对象的值,并把结果保存到集合Set中。
//去除空的对象 Set<String> collect = optionalStream.filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toSet()); System.out.println(collect);
各阶段的类型明细为
5、两个Optional对象的组合
假设有这样一个方法,它接受一个Person和一个Car对象,并以此为条件对外部提供的服务进行查询,
通过一些复杂的业务逻辑,试图找到满足该组合的最便宜的保险公司。
public Insurance findCheapestInsurance(Person person,Car car){ return new Insurance(); }
需要接收两个Optional对象作为参数,返回值是一个Optional<Insurance>对象,如果传入的任何一个参数值为空,
它的返回值亦为空。
public Optional<Insurance> nullSafeFindInsurance1(Optional<Person> person,Optional<Car> car){ if(person.isPresent() && car.isPresent()){ return Optional.of(findCheapestInsurance(person.get(),car.get())); }else{ return Optional.empty(); } }
其实还可以用如下一行语句实现
public Optional<Insurance> nullSafeFindInsurance2(Optional<Person> person,Optional<Car> car){ return person.flatMap(person1 -> car.map(car1 -> findCheapestInsurance(person1,car1))); }
对第一个Optional对象调用flatMap方法,如果它是个空值,传递给它的Lambda表达式就不会执行,
这次调用会直接返回一个空的Optional对象。反之,如果person对象存在,这次调用就会将其作为函数Function的输入,
并按照与flatMap方法的约定返回一个Optional<Insurance>对象。这个函数的函数体会对第二个Optional对象执行map操作,
如果第二个对象不包含car,函数Function就返回一个空的Optional对象,整个nullSafeFindCheapestInsurance方法的返回值
也是一个空的Optional对象。最后,如果person和car对象都存在,那么作为参数传递给map方法的Lambda表达式就能
够使用这两个值安全地调用原始的findCheapestInsurance方法。
6、使用filter剔除特定的值
经常需要调用某个对象的方法,查看它的某些属性。 比如,你可能需要检查保险公司的名称是否为“badao”。
为了以一种安全的方式进行这些操作,你首先需要确定引用指向的Insurance对象是否为null,之后再调用它的getName方法。
Insurance insurance1 = new Insurance(); insurance1.setName("badao"); if(insurance1 !=null && "badao".equals(insurance1.getName())){ System.out.println("ok"); }
可以将其使用filter重构
Optional<Insurance> insurance11 = Optional.of(insurance1); insurance11.filter(insurance -> "badao".equals(insurance.getName())) .ifPresent(x -> System.out.println("ok"));
7、Optional类的方法
方法 | 描述 |
empty | 返回一个空的Optional实例 |
filter | 如果值存在并且满足提供的谓词,就返回包含该值的Optional对象;否则返回一个空的Optional对象 |
flatMap | 如果值存在,就对该值执行提供的mapping函数调用,返回一个Optional类型的值,否则就返回一个空的Optional对象 |
get | 如果值存在,就将该值用Optional封装返回,否则抛出一个NoSuchElementException异常 |
ifPresent | 如果值存在,就执行使用该值的方法调用,否则什么也不做 |
ifPresentOrElse | 如果值存在,就以值作为输入执行对应的方法调用,否则执行另一个不需任何输入的方法 |
isPresent | 如果值存在就返回true,否则返回false |
map | 如果值存在,就对该值执行提供的mapping函数调用 |
of | 将指定值用Optional封装之后返回,如果该值为null,则抛出一个NullPointerException异常 |
ofNullable | 将指定值用Optional封装之后返回,如果该值为null,则返回一个空的Optional对象 |
or | 如果值存在,就返回同一个Optional对象,否则返回由支持函数生成的另一个Optional对象 |
orElse | 如果有值则将其返回,否则返回一个默认值 |
orElseGet | 如果有值则将其返回,否则返回一个由指定的Supplier接口生成的值 |
orElseThrow | 如果有值则将其返回,否则抛出一个由指定的Supplier接口生成的异常 |
stream | 如果有值,就返回包含该值的一个Stream,否则返回一个空的Stream |
8、Optional两个使用示例
避免如果Map中不含指定的键对应的值,它的get方法就会返回一个null
Optional<Object> aa = Optional.ofNullable(map.get("aa"));
Integer.parseInt(String),将String转换为int。在这个例子中,如果String无法解析到对应的整型
该方法就抛出一个NumberFormatException。最后的效果是,发生String无法转换为int时,代码发出一个遭遇非法参数的信号,
唯一的不同是,这次你需要使用try/catch语句,而不是使用if条件判断来控制一个变量的值是否非空
public static Optional<Integer> stringToInt(String s) { try{ //如果String能转换为对应的Integer,将其封装在Optional对象中返回 return Optional.of(Integer.parseInt(s)); }catch (NumberFormatException e){ //否则返回一个空的Optional对象 return Optional.empty(); } }
标签:map,非空,对象,car,Insurance,null,Optional,public From: https://www.cnblogs.com/badaoliumangqizhi/p/17008526.html