一块儿来学Java8(六)——Optional

Optional类是Java8新增的一个类,其做用能够有效避免空指针异常。java

Optional类的代码比较简单,很容易就能看懂,其实质就是一个辅助类,把须要处理的对象作了一层包装,而后再使用Optional中的方法时,能够有效得判断处理对象是否为空,从而作出正确判断。json

接下来咱们看下如何使用Optional。数据结构

建立Optional

建立Optional有3种方式:iphone

  • Optional.empty() 返回一个空的Optional
  • Optional.of(不为null的对象)
  • Optional.ofNullable(能够为null的对象)

若是可以确保入参必定不为null,能够用Optional.of,由于在Optional.of内部会判断是否为null,若是是null则抛出异常。函数

若是不太肯定入参是否为null,能够用Optional.ofNullablepost

对象建立好了,接下来看看如何使用。学习

isPresent和ifPresent

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

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和flatMap

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();

简单的理解就是:

  • optional.map() 会把返回的结果再次放到一个Optional中
  • optional.flatMap() 不会把结果放入放到Optional中,把这个操做交给开发者来处理,让开发者本身返回一个Optional

get,orElse,orElseGet,orElseThrow

  • 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("不能为空")));

Optional实战

{
	"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处理嵌套数据。

按期分享技术干货,一块儿学习,一块儿进步!

相关文章
相关标签/搜索