如何使用Java中的Optional
NullPointerException是非常常见的异常。由于它,程序往往需要大量使用if-else代码块来处理空值,这使得代码看起来不简洁优雅,且不方便自己和他人阅读。本文介绍如何用Optional类来处理null值问题。
Optional类
先来看一段代码:
Stringisocode=user.getAddress().getCountry().getIsocode().toUpperCase();
这段代码在任何一个方法调用时,都有可能抛出NullPointerException。
而通常我们的处理方式是不断地利用if代码块来确保上一步的值不为空并执行下一步代码。
if(user!=null){ Addressaddress=user.getAddress(); if(address!=null){ Countrycountry=address.getCountry(); if(country!=null){ Stringisocode=country.getIsocode(); if(isocode!=null){ isocode=isocode.toUpperCase(); } } } }
嗯,一股切割器cutter的味道。
Optional类是Java8为了解决null值判断问题,借鉴googleguava类库的Optional类而引入的一个同名Optional类,使用Optional类可以避免显式的null值判断(null的防御性检查),避免null导致的NPE(NullPointerException)。
如何创建Optional实例
Optional类没有公共构造函数。但是确提供了三个静态方法在不同情形下根据需求创建Optional实例。
Optional.of()
这个方法要求你传入一个不为空的值(不一定是引用类型,也可以是原始类型),
所以下面这种写法还是会抛出一个NullPointerException异常:
Optional.of(null);
可见Optional并不能完全避免NullPointerException,关键在于你是否正确以及规范地使用它。
但大多数情况下,我们使用Optional正是由于无法确定值是否为空。在这种情况下,我们使用下面这个方法。
Optional.ofNullable()
这个方法允许你传入空值或者非空值。
Optional.empty()
这个方法会返回一个包装空值的Optional实例。也许你会觉得它会有点鸡肋(我一开始也是这么认为的)。
考虑以下代码:
intdividend=10,divisor=0; intresult=dividend/divisor; Optionalo=Optional.of(result);
显然它会在运行期抛出ArithmeticException异常,这使得后续对于o的可能存在的操作因异常而终止。
改写如下:
intdividend=10,divisor=0; Optionalo; try{ intresult=dividend/divisor; o=Optional.of(result); }catch(ArithmeticExceptione){ o=Optional.empty(); }
访问Optional实例的值
get()
它的源码:
publicTget(){ if(value==null){ thrownewNoSuchElementException("Novaluepresent"); } returnvalue; }
当Optional实例包装的是一个空值时,它会抛出NoSuchElementException。
所以在调用get()方法前我们还是需要判断Optional是否包装空值。
使用ifPresent()方法来判断其包装的是否是空值:
publicstaticStringgetGender(Studentstudent){ OptionalstuOpt=Optional.ofNullable(student); if(stuOpt.isPresent()){ returnstuOpt.get().getGender(); } return"Unkown"; }
而这其实是一种很糟糕的写法,因为这种用法不但没有减少null的防御性检查,而且增加了Optional包装的过程,违背了Optional设计的初衷,因此开发中要避免这种糟糕的使用。下文会介绍相对更好的写法。
获取默认值
Optional提供了两种方法来返回默认值。
orElse()
orElse()会在Optional有值时返回它的值,否则就会返回传入的默认值。
publicclassMain{ publicstaticvoidmain(String[]args){ System.out.println(getGender(null)); } publicstaticStringgetGender(Studentstudent){ StudentstuOpt=Optional.ofNullable(student).orElse(newStudent(); returnstuOpt.getGender(); } }
orElseGet()
orElseGet()则稍有不同,它会在Optional有值时返回其值,否则就会执行作为参数传入的Supplier实例的get()方法,并返回其执行结果。
publicclassMain{ publicstaticvoidmain(String[]args){ System.out.println(getGender(null)); } publicstaticStringgetGender(Studentstudent){ StudentstuOpt=Optional.ofNullable(student).orElseGet(Student::new); returnstuOpt.getGender(); } }
两者的不同之处
- orElse()是EAGER的,也就是说无论Optional的值是否为空,它都会执行。
- orElseGet()是LAZY的,只有当Optional的值为空时,才会执行。
由于由以上差异,我们要根据业务场景谨慎选择,尤其是涉及服务调用或数据查询等耗时操作时。
以上就是如何使用Java中的Optional的详细内容,更多关于Java中的Optional的资料请关注毛票票其它相关文章!