目录
- 4. Optional
- 4.1 概述
- 4.2 使用
- 4.2.1 创建对象
- Optional
- ofNullable()
- of()
- empty()
- 4.2.2 安全消费值
- ifPresent
- 4.2.3 获取值
- get()
- 4.2.4 安全获取值
- orElseGet
- orElseThrow
- 4.2.5 过滤
- filter
- 4.2.6 判断
- isPresent
- 4.2.7 数据转换
- map
4. Optional
4.1 概述
我们在编写代码的时候出现最多的就是空指针异常。所以在很多情况下我们需要做各种非空的判断。
例如:
Author author = getAuthor();
if(author!=null){
System.out.println(author.getName());
}
尤其是对象中的属性还是一个对象的情况下。这种判断会更多。
而过多的判断语句会让我们的代码显得臃肿不堪。
所以在JDK8中引入了Optional,养成使用Optional的习惯后你可以写出更优雅的代码来避免空指针异常。
并且在很多函数式编程相关的API中也都用到了Optional,如果不会使用Optional也会对函数式编程的学习造成影响。
所谓的Optional 相当于是把一个数据封装成了Optional对象当中的一个属性。然后我们就去调用 Optional对象相关的方法来进行非空判断。
4.2 使用
4.2.1 创建对象
Optional
就是用方法把数据封装成一个Optional对象,
方法有 Optional.ofNullable() 和 Optional.of() 和 Optional.empty()
Optional就好像是包装类,可以把我们的具体数据封装Optional对象内部。然后我们去使用Optional中封装好的方法操作封装进去的数据就可以非常优雅的避免空指针异常。
ofNullable()
我们一般使用Optional的静态方法ofNullable来把数据封装成一个Optional对象。无论传入的参数是否为null都不会出现问题。
Author author = getAuthor();
Optional<Author> authorOptional = Optional.ofNullable(author);
你可能会觉得还要加一行代码来封装数据比较麻烦。但是如果改造下getAuthor方法,让其的返回值就是封装好的Optional的话,我们在使用时就会方便很多。
而且在实际开发中我们的数据很多是从数据库获取的。Mybatis从3.5版本可以也已经支持Optional了。我们可以直接把dao方法的返回值类型定义成Optional类型,MyBastis会自己把数据封装成Optional对象返回。封装的过程也不需要我们自己操作。
of()
如果你确定一个对象不是空的则可以使用Optional的静态方法of来把数据封装成Optional对象。
Author author = new Author();
Optional<Author> authorOptional = Optional.of(author);
但是一定要注意,如果使用of的时候传入的参数必须不为null。(尝试下传入null会出现什么结果)
empty()
如果一个方法的返回值类型是Optional类型。而如果我们经判断发现某次计算得到的返回值为null,这个时候就需要把null封装成Optional对象返回。这时则可以使用Optional的静态方法empty来进行封装。
Optional.empty()
所以最后你觉得哪种方式穿件对象会更方便呢?
ofNullable
ofNullable()分析图
分析图
分析图:方法返回的对象直接设置成Optional类型就可以了
Optional.of() 分析图
4.2.2 安全消费值
ifPresent
我们获取到一个Optional对象后肯定需要对其中的数据进行使用。这时候我们可以使用其ifPresent方法对来消费其中的值。
这个方法会判断其内封装的数据是否为空,不为空时才会执行具体的消费代码。这样使用起来就更加安全了。
例如,以下写法就优雅的避免了空指针异常。
//把数据封装成一个Optional对象,无论传入的参数是否为null都不会出现问题
Optional<Author> authorOptional = Optional.ofNullable(getAuthor());
//判断该对象的属性值是否为null,为null就不执行System.out.println(author.getName())这行代码
authorOptional.ifPresent(author -> System.out.println(author.getName()));
4.2.3 获取值
get()
如果我们想获取值自己进行处理可以使用get方法获取,但是不推荐。因为当Optional内部的数据为空的时候会出现异常。
分析图
4.2.4 安全获取值
如果我们期望安全的获取值。我们不推荐使用get方法,而是使用Optional提供的以下方法。
orElseGet
获取数据并且设置数据为空时的默认值。如果数据不为空就能获取到该数据。如果为空则根据你传入的参数来创建对象作为默认值返回。
Optional<Author> authorOptional = Optional.ofNullable(getAuthor());
Author author1 = authorOptional.orElseGet(() -> new Author());
分析图 获取到的对象为null和不为null的区别
orElseThrow
获取数据,如果数据不为空就能获取到该数据。如果为空则根据你传入的参数来创建异常抛出。
Optional<Author> authorOptional = Optional.ofNullable(getAuthor());
try {
Author author = authorOptional.orElseThrow((Supplier<Throwable>) () -> new RuntimeException("author为空"));
System.out.println(author.getName());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
分析图,获取到的对象为null就直接抛自定义的异常
4.2.5 过滤
filter
我们可以使用filter方法对数据进行过滤。如果原本是有数据的,但是不符合判断,也会变成一个无数据的Optional对象。
不符合条件的话,原本有数据的对象,也会变成没有数据的对象了
4.2.6 判断
isPresent
我们可以使用isPresent方法进行是否存在数据的判断。如果为空返回值为false,如果不为空,返回值为true。但是这种方式并不能体现Optional的好处,更推荐使用ifPresent方法。
如果在做if判断的时候,对象为null,那么就不会进入后续的操作
4.2.7 数据转换
map
Optional还提供了map可以让我们的对数据进行转换,并且转换得到的数据也还是被Optional包装好的,保证了我们的使用安全。
例如我们想获取作家的书籍集合。