Java Optional的判空操作详解

Java Optional的判空操作详解

目录

Optional判空

代码模拟

Optional常用方法

使用Optional一定比null好吗

Optional 使用场景

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消费型接口,不存在不执行
getT返回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判空操作的资料请关注易知道(ezd.cc)其它相关文章!

推荐阅读