java8 用Optional取代null

如何处理null

怎样做才能避免不期而至的NullPointerException呢?通常,可以在需要的地方添加null的检查(过于激进的防御式检查甚至会在不太需要的地方添加检测代码),并且添加的方式往往各有不同。

null-安全的第一种尝试:深层质疑

 “深层质疑”,原因是它不断重复着一种模式:每次不确定一个变量是否为null时,都需要添加一个进一步嵌套的if块,也增加了代码缩进的层数。很明显,这种方式不具备扩展性,同时还牺牲了代码的可读性。

 

null-安全的第二种尝试:过多的退出语句

 第二种尝试中,试图避免深层递归的if语句块,采用了一种不同的策略:每次遭遇null变量,都返回一个字符串常量“Unknown”。然而,这种方案远非理想,现在这个方法有了四个截然不同的退出点,使得代码的维护异常艰难。

 

使用Optional获取car的Insurance名称

汲取Haskell和Scala的灵感,Java 8中引入了一个新的类java.util.Optional<T>。这是一个封装Optional值的类。

public String getCarInsuranceName(Optional<Person> person){
    return person.flatMap(Person::getCar)
        .flatMap(Car::getInsurance)
        .map(Insurance::getName)
        .orElse("Unknown");//如果Optional的结果值为空,设置默认值
}

 

 

创建Optional对象

1. 声明一个空的Optional

可以通过静态工厂方法Optional.empty,创建一个空的Optional对象:

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

 

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

还可以使用静态工厂方法Optional.of,依据一个非空值创建一个Optional对象:

如果car是一个null,这段代码会立即抛出一个NullPointerException,而不是等到试图访问car的属性值时才返回一个错误。

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

 

3. 可接受null的Optiona

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

如果car是null,那么得到的Optional对象就是个空对象。

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

 

Optional类的方法

 

 

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

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

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

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

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

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

 

 

附:类代码

复制代码
public class Person {
    private Car car;

    public Car getCar() {
        return car;
    }
}

public class Car {
    private Insurance insurance;

    public Insurance getInsurance() {
        return insurance;
    }
}

public class Insurance {
    private String name;

    public String getName() {
        return name;
    }
}
复制代码

 

附:使用Optional重新定义Person/Car/Insurance的数据模型

复制代码
public class Person {
    private Optional<Car> car;//人可能有车,也可能没有车,因此将这个字段声明为Optional

    public Optional<Car> getCar() {
        return car;
    }
}

public class Car {
    private Optional<Insurance> insurance;//车可能进行了保险,也可能没有保险,所以将这个字段声明为Optional

    public Optional<Insurance> getInsurance() {
        return insurance;
    }
}

public class Insurance {
    private String name;//保险公司必须有名字

    public String getName() {
        return name;
    }
}
复制代码

 

文章来源:java8实战 第十章

 

posted @   草木物语  阅读(1588)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示