Optional类是Java8新增的一个类,其做用能够有效避免空指针异常。java
Optional类的代码比较简单,很容易就能看懂,其实质就是一个辅助类,把须要处理的对象作了一层包装,而后再使用Optional中的方法时,能够有效得判断处理对象是否为空,从而作出正确判断。json
接下来咱们看下如何使用Optional。数据结构
建立Optional有3种方式:iphone
若是可以确保入参必定不为null,能够用Optional.of
,由于在Optional.of
内部会判断是否为null,若是是null则抛出异常。函数
若是不太肯定入参是否为null,能够用Optional.ofNullable
。post
对象建立好了,接下来看看如何使用。学习
isPresent()方法判断处理对象是否为null,不为null返回true,源码以下:ui
public boolean isPresent() { return value != null; }
ifPresent方法有一个入参ifPresent(Consumer<? super T> consumer)
,它的意思是若是对象不为null,则运行consumer进行处理,有点相似回调函数。this
String s = "hello"; Optional<String> optional = Optional.of(s); if(optional.isPresent()) { System.out.println("the value is " + optional.get()); }
一样能够写成:指针
optional.ifPresent((val) -> { System.out.println("the value is " + val); });
filter是对处理对象进行判断,若是判断为true,则返回当前Optional,若是为false则返回一个空的Optional对象,其源码以下:
public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); }
filter方法有个参数:Predicate,这是一个函数式接口,所以咱们可使用Lambda表达式来处理。
String s = "hello"; Optional<String> optional = Optional.of(s); boolean exist = optional .filter(val -> "hello1".equals(val)) .isPresent(); System.out.println(exist); // false
map方法的做用能够简单理解成从处理对象中取出其它对象,而后返回一个新的Optional。以下代码所示:
public class OptionalMapTest { static class Goods { private String goodsName; private Company company; ...getter setter } static class Company { private String companyName; ...getter setter } public static void main(String[] args) { Company company = new Company(); company.setCompanyName("Apple"); Goods goods = new Goods(); goods.setGoodsName("iphoneX"); goods.setCompany(company); Optional<Goods> optional = Optional.of(goods); String companyName = optional // 从goods中取出Company,返回一个新的Optional<Company> .map(goodsObj -> goodsObj.getCompany()) // 从company中取出companyName,返回一个新的Optional<String> .map(companyObj -> companyObj.getCompanyName()) // 获得companyName .get(); System.out.println(companyName); } }
什么状况下该使用flatMap呢,咱们把Goods中的的Company对象改为Optional<Company>
。
static class Goods { private String goodsName; private Optional<Company> company; ...getter setter }
此时下面这段代码会编译报错
String companyName = optional // 从goods中取出Company,返回一个新的Optional<Company> .map(goodsObj -> goodsObj.getCompany()) // !!这里会报错 // 从company中取出companyName,返回一个新的Optional<String> .map(companyObj -> companyObj.getCompanyName()) // 获得companyName .get();
主要是这行代码optional.map(goodsObj -> goodsObj.getCompany())
。由于此时返回的是一个Optional<Optional<Company>>
对象。
而咱们须要的是Optional<Company>
对象,这个时候就应该用到flatMap了,只要把optional.map(goodsObj -> goodsObj.getCompany())
改为optional.flatMap(goodsObj -> goodsObj.getCompany())
便可。
String companyName = optional // 从goods中取出Company,返回一个新的Optional<Company> .flatMap(goodsObj -> goodsObj.getCompany()) // 从company中取出companyName,返回一个新的Optional<String> .map(companyObj -> companyObj.getCompanyName()) // 获得companyName .get();
简单的理解就是:
String s = null; Optional<String> optional = Optional.ofNullable(s); System.out.println(optional.get()); // 抛出java.util.NoSuchElementException: No value present
针对这种状况,有几种处理方式
方式1:使用isPresent()
String s = null; Optional<String> optional = Optional.ofNullable(s); if (optional.isPresent()) { System.out.println(optional.get()); } else { System.out.println("默认值"); }
方式2:使用orElse(默认值)
String s = null; Optional<String> optional = Optional.ofNullable(s); System.out.println(optional.orElse("默认值"));
orElse(默认值)的意思是若是Optional中的值为null,则返回给定的默认值。
方式3:使用orElseGet(Supplier)
String s = null; Optional<String> optional = Optional.ofNullable(s); System.out.println(optional.orElseGet(() -> "默认值"));
orElse(Supplier)的意思是若是Optional中的值为null,则执行指定的Supplier接口,因为Supplier是个函数式接口,所以可使用Lambda表达式代替。
由此看来,方式2和方式3的处理是比较优雅的。
方式2和方式3的区别在于,方式3能够延迟返回,只有值为null的状况下才会触发() -> "默认值"
,从而避免生成无用对象,方式2无论如何都生成了"默认值"这个字符串对象。下面的例子能够说明:
String s = "1"; Optional<String> optional = Optional.ofNullable(s); System.out.println(optional.orElse(getDefault()));
打印:
生成了字符串对象 1
即便Optional中的值不为null,但仍是执行了getDefault(),这彻底不必,再来看下使用orElseGet
String s = "1"; Optional<String> optional = Optional.ofNullable(s); System.out.println(optional.orElseGet(() -> getDefault()));
打印:1
接着再看下orElseThrow,若是值为null,则直接抛出异常
String s = null; Optional<String> optional = Optional.ofNullable(s); System.out.println(optional.orElseThrow(() -> new NullPointerException("不能为空")));
{ "user": { "age": 20 ,"name": "Jim" ,"address": { "province": "浙江省" ,"postcode": "111111" } } }
假设有这样一个json字符串,如今要获取postcode信息。若是不用Optional的话,要写各类if…else语句,还要判断字段是否存在。
String postcode = "unknown"; JSONObject user = jsonObj.getJSONObject("user"); if (user != null) { JSONObject address = user.getJSONObject("address"); if (address != null) { String code = address.getString("postcode"); if (postcode != null) { postcode = code; } } } System.out.println(postcode);
可是用Optional能够这样写:
JSONObject jsonObj = JSON.parseObject(json); String postcode = Optional.ofNullable(jsonObj) .flatMap(jsonObject -> Optional.ofNullable(jsonObject.getJSONObject("user"))) .flatMap(jsonObject -> Optional.ofNullable(jsonObject.getJSONObject("address"))) .flatMap(jsonObject -> Optional.ofNullable(jsonObject.getString("postcode"))) .orElse("unknown"); System.out.println(postcode);
注意,这里要使用flatMap,由开发者手动返回一个Optional对象,若是使用map的话则返回Optional<Optional<JSONObject>>
。
最后一句.orElse("unknown")表示若是一路走下来没有找到值,则返回一个默认值。
Optional的优点是处理嵌套数据结构,如这里的json数据。假如这段json数据结构不是完整的,postcode字段不存在,或者整个address字段都不存在,在没法保证嵌套数据中的值是否存在的状况下,使用Optional是个不错的选择。它都能确保有个正确的返回值。
本篇主要介绍了Optional类的用法,同时演示了如何使用Optional处理嵌套数据。
按期分享技术干货,一块儿学习,一块儿进步!