深度解析 Java 的 Optional 类(下)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 深度解析 Java 的 Optional 类(下)

所以用 ofNullable()newTitle 转换一个 Optional

image.png

  • nullofNullable()返回Optional.empty()
  • 调用 orElseThrow()
  • 1639639428(1).png
  • 如果 newTitle 的值是 null,会得到异常。

这里我们并没有把 title 保存成 Optional,但通过应用 Optional 的功能,我们仍对字段加了约束。

在这个方案里边,你仍然可能会得到一个异常。不同的是,错误产生那刻(向 setTitle() 传 null 值时)就抛异常,而不发生在其它时刻。使用 EmptyTitleException 有助于定位 BUG。

Person 字段的限制:如果把值设 null,程序会自动把将它赋值成一个空的 Person 对象。先前我们也用过类似的方法把字段转换成 Option,但这里我们是在返回结果的时候使用 orElse(new Person()) 插入一个空的 Person 对象替代了 null。


在 Position 里,没有创建一个表示“空”的标志位或者方法,因为 person 字段的 Person 对象为空,就表示这个 Position 是个空位置。之后,你可能会发现你必须添加一个显式的表示“空位”的方法,但是正如 YAGNI (You Aren’t Going to Need It,你永远不需要它)所言,在初稿时“实现尽最大可能的简单”,直到程序在某些方面要求你为其添加一些额外的特性,而不是假设这是必要的。


虽然使用了 Optional,可以免受 NullPointerExceptions,但 Staff 类对此毫不知情。

// typeinfo/Staff.java
import java.util.*;
public class Staff extends ArrayList<Position> {
    public void add(String title, Person person) {
        add(new Position(title, person));
    }
    public void add(String... titles) {
        for (String title : titles)
            add(new Position(title));
    }
    public Staff(String... titles) {
        add(titles);
    }
    public Boolean positionAvailable(String title) {
        for (Position position : this)
            if (position.getTitle().equals(title) &&
                    position.getPerson().empty)
                return true;
        return false;
    }
    public void fillPosition(String title, Person hire) {
        for (Position position : this)
            if (position.getTitle().equals(title) &&
                    position.getPerson().empty) {
                position.setPerson(hire);
                return;
            }
        throw new RuntimeException(
                "Position " + title + " not available");
    }
    public static void main(String[] args) {
        Staff staff = new Staff("President", "CTO",
                "Marketing Manager", "Product Manager",
                "Project Lead", "Software Engineer",
                "Software Engineer", "Software Engineer",
                "Software Engineer", "Test Engineer",
                "Technical Writer");
        staff.fillPosition("President",
                new Person("Me", "Last", "The Top, Lonely At"));
        staff.fillPosition("Project Lead",
                new Person("Janet", "Planner", "The Burbs"));
        if (staff.positionAvailable("Software Engineer"))
            staff.fillPosition("Software Engineer",
                    new Person(
                            "Bob", "Coder", "Bright Light City"));
        System.out.println(staff);
    }
}

输出结果:

[Position: President, Employee: Me Last The Top, Lonely
At, Position: CTO, Employee: <Empty>, Position:
Marketing Manager, Employee: <Empty>, Position: Product
Manager, Employee: <Empty>, Position: Project Lead,
Employee: Janet Planner The Burbs, Position: Software
Engineer, Employee: Bob Coder Bright Light City,
Position: Software Engineer, Employee: <Empty>,
Position: Software Engineer, Employee: <Empty>,
Position: Software Engineer, Employee: <Empty>,
Position: Test Engineer, Employee: <Empty>, Position:
Technical Writer, Employee: <Empty>]

有些地方你可能还是要测试引用是不是 Optional,这跟检查是否为 null 没什么不同。但是在其它地方(例如本例中的 toString() 转换),你就不必执行额外的测试了,而可以直接假设所有对象都是有效的。

标记接口

有时使用标记接口表示空值更方便,把它的名字当做标签来用即可

image.png

用接口取代具体类,即可使用 DynamicProxy 自动创建 Null 对象。

假设有一个 Robot 接口

image.png

Operation 包含一个描述和一个命令(这用到了命令模式)。

定义成函数式接口的引用,所以可以把 lambda 表达式或者方法的引用传给 Operation 的构造器:

image.png

现在我们可以创建一个扫雪 Robot

image.png

假设许多不同类型的 Robot,想让每种 Robot 都创建一个 Null 对象来执行一些特殊的操作

本例中,提供 Null 对象所代表 Robot 的确切类型信息。这些信息是通过动态代理捕获的:

image.png

如果你需要一个空 Robot 对象,只需调用 newNullRobot(),并传递需要代理的 Robot 类型。这个代理满足了 RobotNull 接口的需要,并提供了它所代理的类型的确切名字。

目录
相关文章
|
13天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
43 2
|
17天前
|
Java
轻松上手Java字节码编辑:IDEA插件VisualClassBytes全方位解析
本插件VisualClassBytes可修改class字节码,包括class信息、字段信息、内部类,常量池和方法等。
66 6
|
1天前
|
Java 数据库连接 开发者
Java中的异常处理机制:深入解析与最佳实践####
本文旨在为Java开发者提供一份关于异常处理机制的全面指南,从基础概念到高级技巧,涵盖try-catch结构、自定义异常、异常链分析以及最佳实践策略。不同于传统的摘要概述,本文将以一个实际项目案例为线索,逐步揭示如何高效地管理运行时错误,提升代码的健壮性和可维护性。通过对比常见误区与优化方案,读者将获得编写更加健壮Java应用程序的实用知识。 --- ####
|
4天前
|
数据采集 存储 Web App开发
Java爬虫:深入解析商品详情的利器
在数字化时代,信息处理能力成为企业竞争的关键。本文探讨如何利用Java编写高效、准确的商品详情爬虫,涵盖爬虫技术概述、Java爬虫优势、开发步骤、法律法规遵守及数据处理分析等内容,助力电商领域市场趋势把握与决策支持。
|
7天前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
|
9天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
10天前
|
Java 测试技术 API
Java 反射机制:深入解析与应用实践
《Java反射机制:深入解析与应用实践》全面解析Java反射API,探讨其内部运作原理、应用场景及最佳实践,帮助开发者掌握利用反射增强程序灵活性与可扩展性的技巧。
|
15天前
|
存储 算法 Java
Java Set深度解析:为何它能成为“无重复”的代名词?
Java的集合框架中,Set接口以其“无重复”特性著称。本文解析了Set的实现原理,包括HashSet和TreeSet的不同数据结构和算法,以及如何通过示例代码实现最佳实践。选择合适的Set实现类和正确实现自定义对象的hashCode()和equals()方法是关键。
25 4
|
16天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
11天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####

推荐镜像

更多