美文网首页
Java8 用Optional取代null

Java8 用Optional取代null

作者: 巴巴11 | 来源:发表于2020-03-25 22:51 被阅读0次

避免用null来表示变量的缺失!

带来的问题:

Null是错误之源。

NullPointerException是目前Java程序开发中最典型的异常。

它会使你的代码膨胀。
它让你的代码充斥着深度嵌套的null检查,代码的可读性糟糕透顶。

它自身是毫无意义的。
null自身没有任何的语义,尤其是,它代表的是在静态类型语言中以一种错误的方式对缺失变量值的建模。

它破坏了Java的哲学。
Java一直试图避免让程序员意识到指针的存在,唯一的例外是: null指针。

它在Java的类型系统上开了个口子。
null并不属于任何类型,这意味着它可以被赋值给任意引用类型的变量。这会导致问题,
原因是当这个变量被传递到系统中的另一个部分后,你将无法获知这个null变量最初的
赋值到底是什么类型。

java.util.Optional<T>

在对象模型中使用Optional,无法序列化
Optional的设计初衷仅仅是要支持能返回Optional对象的语法
由于Optional类设计时就没特别考虑将其作为类的字段使用,所以它也并未实现Serializable接口。

可以将Optional看成最多包含一个元素的Stream对象

如何创建Optional对象:

  1. 声明一个空的Optional

静态工厂方法Optional.empty

Optional<Car> optCar = Optional.empty();

  1. 依据一个非空值创建Optional

静态工厂方法Optional.of

Optional<Car> optCar = Optional.of(car); // 如果car是一个null,这段代码会立即抛出一个NullPointerException

  1. 可接受null的Optional

静态工厂方法Optional.ofNullable,可以创建一个允许null值的Optional对象

Optional<Car> optCar = Optional.ofNullable(car);

使用 map 从 Optional 对象中提取和转换值

String name = null;
if(insurance != null){
name = insurance.getName();
}

# 改进
Optional<Insurance> optInsurance = Optional.ofNullable(insurance);
Optional<String> name = optInsurance.map(Insurance::getName);

使用 flatMap 链接 Optional 对象

public String getCarInsuranceName(Person person) {
return person.getCar().getInsurance().getName();
}

# 改进
public String getCarInsuranceName(Optional<Person> person) {
return person.flatMap(Person::getCar)
    .flatMap(Car::getInsurance)
    .map(Insurance::getName)
    .orElse("Unknown");
}

Optional类提供了多种方法读取Optional实例中的变量值:

get()是这些方法中最简单但又最不安全的方法。
如果变量存在,它直接返回封装的变量值,否则就抛出一个NoSuchElementException异常。
所以,除非非常确定Optional变量一定包含值,否则使用这个方法是个相当糟糕的主意。
此外,这种方式即便相对于嵌套式的null检查,也并未体现出多大的改进。

orElse(T other),允许在Optional对象不包含值时提供一个默认值。

orElseGet(Supplier<? extends T> other)是orElse方法的延迟调用版, 
Supplier方法只有在Optional对象不含值时才执行调用。
如果创建默认值是件耗时费力的工作,你应该考虑采用这种方式(借此提升程序的性能),
或者你需要非常确定某个方法仅在Optional为空时才进行调用,
也可以考虑该方式(这种情况有严格的限制条件)。

orElseThrow(Supplier<? extends X> exceptionSupplier) 
和get方法非常类似,
它们遭遇Optional对象为空时都会抛出一个异常,
但是使用orElseThrow你可以定制希望抛出的异常类型。

ifPresent(Consumer<? super T>),
让你能在变量值存在时执行一个作为参数传入的方法,否则就不进行任何操作。

Optional类和Stream接口的相似之处,远不止map和flatMap这两个方法。
还有第三个方法filter,它的行为在两种类型之间也极其相似

isPresent方法,如果Optional对象包含值,该方法就返回true

使用 filter 剔除特定的值

Insurance insurance = ...;
if(insurance != null && "CambridgeInsurance".equals(insurance.getName())){
System.out.println("ok");

# 改进
Optional<Insurance> optInsurance = ...;
optInsurance.filter(insurance ->
"CambridgeInsurance".equals(insurance.getName()))
.ifPresent(x -> System.out.println("ok"));


public String getCarInsuranceName(Optional<Person> person, int minAge) {
return person.filter(p -> p.getAge() >= minAge)
    .flatMap(Person::getCar)
    .flatMap(Car::getInsurance)
    .map(Insurance::getName)
    .orElse("Unknown");
}

Optional类的方法:

empty 
返回一个空的 Optional 实例

filter
如果值存在并且满足提供的谓词,就返回包含该值的 Optional 对象;否则返回一个空的Optional对象

flatMap
如果值存在,就对该值执行提供的 mapping 函数调用,返回一个 Optional 类型的值,否则就返回一个空的 Optional 对象

get 
如果该值存在,将该值用 Optional 封装返回,否则抛出一个 NoSuchElementException 异常

ifPresent 
如果值存在,就执行使用该值的方法调用,否则什么也不做

isPresent 
如果值存在就返回 true,否则返回 false

map 
如果值存在,就对该值执行提供的 mapping 函数调用

of
将指定值用 Optional 封装之后返回,如果该值为 null,则抛出一个 NullPointerException异常

ofNullable 
将指定值用 Optional 封装之后返回,如果该值为 null,则返回一个空的 Optional 对象

orElse 
如果有值则将其返回,否则返回一个默认值

orElseGet 
如果有值则将其返回,否则返回一个由指定的 Supplier 接口生成的值

orElseThrow 
如果有值则将其返回,否则抛出一个由指定的 Supplier 接口生成的异常

实战:

public static Optional<Integer> stringToInt(String s) {
try {
return Optional.of(Integer.parseInt(s));
} catch (NumberFormatException e) {
return Optional.empty();
}
}

Optional<Object> value = Optional.ofNullable(map.get("key"));

public int readDuration(Properties props, String name) {
return Optional.ofNullable(props.getProperty(name))
.flatMap(OptionalUtility::stringToInt)
.filter(i -> i > 0)
.orElse(0);
}

总结:

null引用在历史上被引入到程序设计语言中,目的是为了表示变量值的缺失。

Java 8中引入了一个新的类java.util.Optional<T>,对存在或缺失的变量值进行建模。

可以使用静态工厂方法Optional.empty、 Optional.of以及Optional.ofNullable创建Optional对象。

Optional类支持多种方法,比如map、 flatMap、 filter,它们在概念上与Stream类中对应的方法十分相似。

使用Optional会迫使你更积极地解引用Optional对象,以应对变量值缺失的问题,最终,你能更有效地防止代码中出现不期而至的空指针异常。

使用Optional能帮助你设计更好的API,用户只需要阅读方法签名,就能了解该方法是否接受一个Optional类型的值。

相关文章

  • Java8笔记(5)

    Java8笔记(5) 用 Optional 取代 null 如何为缺失的值建模 假设你需要处理下面这样的嵌套对象,...

  • Java8 用Optional取代null

    避免用null来表示变量的缺失! 带来的问题: java.util.Optional 在对象模型中使用Opt...

  • 用Optional取代null

    创建Optional对象 Optional.empty():声明一个空Optional Optional.of()...

  • 用Optional取代null

    null引发的问题以及为什么要避免null引用 先看一个例子 意思也就是说获取一个人的车的保险公司的名称。可以看到...

  • java8(六)用 Optional 取代 null

    一、null带来了哪些问题? 1)NullPointerException 是目前Java程序开发中最典型的异常。...

  • Optional源码分析(未完)

    Optional源码分析(未完) Optional 类是Java8的新特性,Optional是一个可以为null的...

  • Optional 取代 null?

    我们在平时编程的时候,遇到的一类Exception 要数 NullPointException, 所以我们很经常...

  • 学习Optional 类

    1.介绍 Optional类是Java8为了解决null值判断问题,,使用Optional类可以避免显式的null...

  • Optional类

    Optional类为Java8新引入的一个类,Optional是一个可以为null的容器对象,Optional中的...

  • 【java8新特性 简述】Optional

    Optional类是Java8为了解决null值判断问题,借鉴google guava类库的Optional类而引...

网友评论

      本文标题:Java8 用Optional取代null

      本文链接:https://www.haomeiwen.com/subject/omzxuhtx.html