JAVA在1.8版本推出Optional,官方文档将其描述为可能包含或不包含非空值的容器对象,目前Optional用于避免程序出现异常NullPointerException,感兴趣的可以了解一下
Optional判空
JAVA在1.8版本推出Optional,官方文档将其描述为可能包含或不包含非空值的容器对象,目前Optional用于避免程序出现异常NullPointerException。
代码模拟
// 下面所有类省略set,get方法
public class Employee {
private String employeeName;
private Team team;
}
public class Team {
private String teamName;
private Department department;
public Team(String teamName) {
this.teamName = teamName;
}
}
public class Department {
private String departmentName;
private Company company;
}
public class Company {
private String companyName;
}
测试代码
// 在创建时因为没有初始化Team对象的Department属性,导致后续调用空指针
public void testCompany(){
Employee employee = new Employee();
employee.setEmployeeName("zhangsan");
employee.setTeam(new Team("xxx产品组"));
System.out.println(employee.getTeam().getDepartment().getCompany().getCompanyName());
}
这时如果我们采用传统方式一般判空代码如下
public void testCompanyAvoidNPE(){
Employee employee = new Employee();
employee.setEmployeeName("zhangsan");
employee.setTeam(new Team("xxx产品组"));
Team team = employee.getTeam();
if (team == null){
System.out.println("异常拉,参数为空!");
return;
}
Department department = team.getDepartment();
if (department == null){
System.out.println("异常拉,参数为空!");
return;
}
Company company = department.getCompany();
if (company == null){
System.out.println("异常拉,参数为空!");
return;
}
String companyName = company.getCompanyName();
System.out.println(companyName);
}
显然这种判空代码造成了业务代码膨胀,代码可读性极低,所以在这种场景下我们需要学习1.8推出的判空容器对象Optional。
Optional常用方法
创建 Optional 对象
JAVA提供了三个静态方法用于构建Optional对象如下所示
返回值 | 方法和描述 |
---|---|
static <T> Optional<T> | empty() 返回一个空的 Optional实例。 |
static <T> Optional<T> | of(T value) 返回具有 Optional的当前非空值的Optional。 |
static <T> Optional<T> | ofNullable(T value) 返回一个 Optional指定值的Optional,如果非空,则返回一个空的 Optional 。 |
public void createOptionalObject(){
System.out.println(Optional.empty());
// 传null报空指针
// System.out.println(Optional.of(null));
System.out.println(Optional.of(new String("1111")));
// 传null调用Optional.empty()
System.out.println(Optional.ofNullable(null));
System.out.println(Optional.ofNullable(new Content("111","测试内容")));
}
class Content {
private String id;
private String value;
public Content() {
}
public Content(String id, String value) {
this.id = id;
this.value = value;
}
// 省略get,set方法
}
执行结果如下
Optional.empty
Optional[1111]
Optional.empty
Optional[Content{id='111', value='测试内容'}]
在真正使用时建议使用ofNullable,因为它能处理空值或者非空值,代码如下
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
常用功能方法
方法名 | 返回值 | 功能描述 |
---|---|---|
isPresent() | boolean | 判断Optional对象是否存在,存在true不存在false |
ifPresent(Consumer<? super T> consumer) | void | 如果Optional对象存在执行consumer消费型接口,不存在不执行 |
get | T | 返回Optional对象封装的对象T数据,注意实际对象可能为空会抛出异常 |
orElse(T other) | T | 如果Optional对象存在则返回封装的对象数据,如果不存在返回T other数据,相当于不存在给默认值 |
orElseGet(Supplier<? extends T> other) | T | 是orElse方法的升级版,区别在于orElse方法传入的是一个固定默认值,而此方法是一个供给型函数方法,如果Optional对象为空则执行other的方法逻辑 |
orElseThrow(Supplier<? extends X> exceptionSupplier) | <X extends Throwable>T | 一样是orElse方法的升级版,当Optional对象为空执行exceptionSupplier方法,最后抛出异常 |
filter(Predicate<? super T> predicate) | Optional<T> | 当Optional对象满足predicate断言函数中的匹配规则则返回,否则返回空Optional |
map(Function<? super T,? extends U> mapper) | <U> Optional<U> | 能够将Optional的对象值处理转换为另一个实例对象值,并生成新类型的Optional对象,如果生成的新对象为null,则返回一个空Optional对象 |
flatMap(Function<? super T,Optional<U>> mapper) | <U> Optional<U> | 和map类似,不过map操作的是具体对象,而flatMap返回的是Optional封装过的对象 |
代码演示如下
public void testOptionFunction(){
//===============================isPresent()================================
// false
System.out.println(Optional.empty().isPresent());
// Optional[Content{id='222', value='测试'}]
System.out.println(Optional.ofNullable(new Content("222","测试")));
//===============================ifPresent()================================
// 不为空打印:Content{id='222', value='测试'} 为空不执行
Optional.ofNullable(new Content("222","测试")).ifPresent(e->{
System.out.println("不为空打印:"+e);
});
//===============================get()================================
// NoSuchElementException: No value present
try {
System.out.println(Optional.empty().get());
}catch (Exception e){
e.printStackTrace();
}
// Content{id='222', value='测试'}
System.out.println(Optional.ofNullable(new Content("222","测试")).get());
//===============================orElse()================================
// Content{id='0', value='默认'}
System.out.println(Optional.empty().orElse(new Content("0","默认")));
//===============================orElseGet()================================
// Content{id='333', value='测试orElseGet'}
System.out.println(Optional.empty().orElseGet(() -> {
Content content = new Content("333", "测试orElseGet");
return content;
}));
// Content{id='222', value='测试'}
System.out.println(Optional.ofNullable(new Content("222", "测试")).orElseGet(() -> {
Content content = new Content("444", "测试orElseGet");
return content;
}));
//===============================orElseThrow()================================
// java.lang.Exception: 参数为空
try {
Optional.empty().orElseThrow(()->{
return new Exception("参数为空");
});
} catch (Exception e) {
e.printStackTrace();
}
//===============================filter()================================
// "555".equals(e.getId()); Optional[Content{id='555', value='测试'}]
// "5565".equals(e.getId()); Optional.empty
System.out.println(Optional.ofNullable(new Content("555", "测试")).filter(e -> {
return "5565".equals(e.getId());
}));
}
map和flatMap
public void testOptionMapFunction(){
Optional<Content> optionalContent = Optional.ofNullable(new Content("777","测试Map"));
Optional<Content> optionalContent1 = optionalContent.map(e -> {
String id = e.getId();
String value = e.getValue();
return e;
});
Optional<Content> optionalContent2 = optionalContent.flatMap(e -> {
String id = e.getId();
String value = e.getValue();
// 不同点在这里,一个是可以转换为另一个实例对象,一个是转换为Optional包装对象
return Optional.of(e);
});
// 最终效果实现效果类似
System.out.println(optionalContent1);
System.out.println(optionalContent2);
}
使用Optional一定比null好吗
这个显然是不对的,如果使用方式如下所示,其实和null的直接判空没有区别
public static void main(String[] args) {
Optional<Content> optionalContent = Optional.ofNullable(null);
// 直接报错
optionalContent.get();
}
// 升级写法
public static void main(String[] args) {
Optional<Content> optionalContent = Optional.ofNullable(null);
// 非空判断
if (optionalContent.isPresent()){
System.out.println(optionalContent.get());
}
}
null的直接判空
public static void main(String[] args) {
Content content = new Content();
if (content != null){
System.out.println(content);
}
}
正确写法如下所示
public static void main(String[] args) {
Optional<Content> optionalContent = Optional.ofNullable(null);
// 非空时执行消费型接口里面的逻辑
optionalContent.ifPresent(content -> {
System.out.println(content);
});
}
到这里有人可能说,如果if{}else{}里面都需要写逻辑如何处理呢
public static void main(String[] args) {
Optional<Content> optionalContent = Optional.ofNullable(null);
Content content = optionalContent.map(e -> {
// 做一些业务
// 返回值可以为任意类型值,可以返回字符串,不过orElseGet需要返回字符串保持一致即可
return e;
}).orElseGet(() -> {
// 做一些业务
return new Content("0", "默认值");
});
System.out.println(content);
}
Optional 使用场景
减少繁琐的非空判断
如前面提到的testCompanyAvoidNPE方法中的例子,就可以采用Optional来简化
public void testCompanyAvoidNPE2(){
Employee employee = new Employee();
employee.setEmployeeName("zhangsan");
employee.setTeam(new Team("xxx产品组"));
// 这里相当于是链式操作
String companyName = Optional.ofNullable(employee)
.map(employee1 -> employee1.getTeam())
.map(team -> team.getDepartment())
.map(department -> department.getCompany())
.map(company -> company.getCompanyName())
.orElse("no company");
System.out.println(companyName);
}
设置默认值兜底
// 原始方法
public String setDefaultValue1(Content content){
if (ObjectUtils.isEmpty(content)){
return "0";
}
if (StringUtils.isEmpty(content.getId())){
String id = "0";
content.setId(id);
}
return content.getId();
}
// 采用Optional
public String setDefaultValue2(Content content){
String id = Optional.ofNullable(content)
.map(content1 -> content1.getId())
.orElse("0");
return id;
}
Optional 尽量只用作方法的返回类型
注意我们采用Optional的最终目的是避免程序中出现null对象异常的情况,所以我们封装方法的时候可以采用Optional 作为方法的返回值类型,但也要注意Optional虽好但不要滥用,适当使用即可。
以上就是Java Optional的判空操作详解的详细内容,更多关于Java Optional判空操作的资料请关注编程学习网其它相关文章!
本文标题为:Java Optional的判空操作详解
基础教程推荐
- ConditionalOnProperty配置swagger不生效问题及解决 2023-01-02
- springboot自定义starter方法及注解实例 2023-03-31
- Java文件管理操作的知识点整理 2023-05-19
- Java并发编程进阶之线程控制篇 2023-03-07
- Java数据结构之对象比较详解 2023-03-07
- java基础知识之FileInputStream流的使用 2023-08-11
- Java实现查找文件和替换文件内容 2023-04-06
- java实现多人聊天系统 2023-05-19
- JDK数组阻塞队列源码深入分析总结 2023-04-18
- Java实现线程插队的示例代码 2022-09-03