在写程序时,经常需要对创建的对象或属性进行null值判断,但是有时可能会疏忽没有对null进行判断,就会引发空指针问题,null值在程序设计语言中,是为了表示变量值的缺失;
java8中引入了Optional<T>,可以表示值的存在与不存在(null),对存在或不存在的变量值进行建模,并且可以避免空指针异常.
以下实例演示可以说明Optional<T>可以很好解决类型T为null时的问题。
package com.xiaomifeng1010.rbacboot.common.util;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;
import java.util.Optional;
import java.util.function.Supplier;
/**
* @author xiaomifeng1010
* @version 1.0
* @date: 2020/3/21 16:18
*/
public class Java8Optional {
/**
* 在java8之前如果要保存Info对象,需要做多层非空检查,多层if嵌套
* @param info
*/
// public void savaInfo(Info info){
// if (info !=null){
// if (info.getAddress() != null) {
则保存info
// }
// }
//
// }
/**
* 过多的退出语句
* @param info
*/
// public void savaInfo2(Info info){
// if (info==null){
// return;
// }
// if (info.getAddress()==null){
// return;
// }
// }
// Optional可以解决判断null问题
/**
* 创建Optional对象
*/
public void createOptional(){
// 创建一个空白的Optional
Optional<Address> optionalAddress=Optional.empty();
// 依据一个非空值创建Optional(new Address()不能为null)
Optional<Address> optionalAddress2=Optional.of(new Address());
// 可接受null值创建Optional(当new Address()为null时,调用empty()方法,创建一个空白Optional对象)
Optional<Address> getOptionalAddress3= Optional.ofNullable(new Address());
}
/**
* 使用map(同Stream API中的中间操作map)从optional对象中提取和转换值
*/
public void mapToOptional(){
Optional<Address> addressOptional=Optional.ofNullable(new Address("南京路","20号"));
// 直接从Optional<Address>中获取Address类中street属性
Optional<String> street=addressOptional.map(Address::getStreet);
}
public void flatMapToOptional(){
Info info=new Info();
Optional<Info> infoOptional=Optional.of(info);
// 再使用map就会报错,因为map转换输出的还是一个optional对象,会造成原本的optional里面存放optional对象
// infoOptional.map(info -> info.getOptionalAddress());
// 可以使用flatMap方法从Info类中获取Optional<Address>,然后获取Address类型的street属性
Optional<String> stringOptional=infoOptional.flatMap(Info::getOptionalAddress).map(Address::getStreet);
System.out.println(stringOptional);
}
/**
* 默认行为及解引用 optional对象
*/
@Test
public void defaultValue(){
Optional<Address> addressOptional= Optional.ofNullable(null);
// 获取街道名,如果无,则设置为"上海路"
String street = addressOptional.map(Address::getStreet).orElse("上海路");
System.out.println(street);
}
public static void main(String[] args) {
Info info=new Info();
info.setUsername("xiaomifeng1010");
info.setPassword("123456");
info.setAge(30);
info.setOptionalAddress(Optional.of(new Address("广州路","12号")));
boolean present=info.getOptionalAddress().filter(address -> address.
getDoor().contains("23"))
// isPresent():如果存在值,则为true.不存在值,则为false
.isPresent();
System.out.println(present);
// address为null,过滤会报错,需要抛出异常,并处理
info.setOptionalAddress(Optional.empty());
Address address=null;
try {
address= info.getOptionalAddress().filter(address1 -> address1.getDoor().contains("34"))
.orElseThrow(new Supplier<Throwable>() {
@Override
public Throwable get() {
return new Exception("哎呀,出错了");
}
});
} catch (Throwable throwable) {
throwable.printStackTrace();
}
// Info类中的年龄为30,不满足大于50,所以不会找到地址信息,输出“不存在”
System.out.println(getSteet(Optional.of(info),50));
}
public static String getSteet(Optional<Info> info,int minAge){
return info.filter(information -> information.getAge()>= minAge).
flatMap(Info::getOptionalAddress)
.map(Address::getStreet).orElse("不存在");
}
}
/**
* 自定义一个类Info
*/
@Data
class Info{
private String username;
private String password;
private Integer age;
// private Address address;
/**
* 为了解决空指针问题(即Address可能为null的情况),创建Optional对象,当Address未赋值初始化,
* 会生成一个empty(空白)的Optional对象,而不会产生null(可以允许Address对象缺失)
*
**/
Optional<Address> optionalAddress;
}
/**
* 住址对象
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
class Address{
/**
* 街道
*/
private String street;
/**
* 门牌
*/
private String door;
}
Optional<T>对应的常用方法:
方法 | 描述 |
| 返回一个空的 Optional 实例 |
| 将指定值用 Optional 封装之后返回,如果该值为 null,则抛出一个 NullPointerException 异常 |
| 将指定值用 Optional 封装之后返回,如果该值为 null,则返回一个空的 Optional 对象 |
| 如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty() |
| 与map 类似,要求返回值必须是Optional |
| 如果值存在并且满足提供的断言, 就返回包含该值的 Optional 对象;否则返回一个空的 Optional 对象 |
| 如果该值存在,将该值用 Optional 封装返回,否则抛出一个 NoSuchElementException 异常 |
| 如果值存在,就执行使用该值的方法调用,否则什么也不做 |
| 如果值存在就返回 true,否则返回 false |
| 如果有值则将其返回,否则返回一个默认值(即 |
| 如果有值则将其返回,否则返回一个由指定的 Supplier 接口生成的值 |
| 如果有值则将其返回,否则抛出一个由指定的 Supplier 接口生成的异常 |