Spring Boot 3.x 中 @NotNull 与 @NonNull 的深度解析

在 Java 开发领域,尤其是在 Spring Boot 生态系统中,空指针异常(NPEs)始终是一个顽固的挑战。这些运行时错误可能导致应用程序崩溃、数据不一致以及糟糕的用户体验。为了应对这一问题,Java 社区开发了各种空安全机制,其中注解扮演着至关重要的角色。

本文将深入探讨 Spring Boot 3.x 与 Jakarta 中用于空安全的两个关键注解:@NotNull 和 @NonNull。我们将探索它们的起源、用途和实际应用,为您提供编写更健壮和防错代码的知识。

空安全概览

在深入了解具体细节之前,让我们先了解一下背景:

  • • 空引用:由 Tony Hoare 于 1965 年引入,他后来称之为他的“价值十亿美元的错误”。

  • • Java 的方法:与一些具有内置空安全的现代语言不同,Java 依赖于注解和静态分析工具。

  • • Spring Boot 3.2:拥抱 Jakarta EE 9+,带来了包名更改和增强的空安全特性。

注解深度解析

@NotNull
  • • 起源:Jakarta Bean Validation API

  • • jakarta.validation.constraints.NotNull

  • • 用途:运行时验证,确保值不为 null

  • • 行为:与验证器一起使用时,在运行时触发验证

@NonNull
  • • 起源:Spring Framework

  • • org.springframework.lang.NonNull

  • • 用途:静态分析和空安全文档

  • • 行为:供 IDE 和静态分析工具使用;无运行时影响

对比分析

让我们分解关键差异:

  • • 验证机制

    • • @NotNull:主动运行时检查

    • • @NonNull:被动编译时提示

  • • 框架集成

    • • @NotNull:广泛认可(Jakarta EE、Spring、Hibernate)

    • • @NonNull:Spring 特有,但受许多 IDE 尊重

  • • 性能影响

    • • @NotNull:由于验证,运行时开销略有增加

    • • @NonNull:无运行时影响

  • • 用例

    • • @NotNull:输入验证,尤其是外部数据

    • • @NonNull:内部代码约定和 API 文档

  • • 失败行为

    • • @NotNull:可能抛出 ConstraintViolationException

    • • @NonNull:依赖于代码中的正确 null 检查

综合示例

让我们在 Spring Boot 中使用这两个注解探索一个实际场景。

import jakarta.validation.constraints.NotNull;
import jakarta.validation.Valid;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.List;
import java.util.Optional;@Service
@Validated
publicclassProductService {privatefinal ProductRepository productRepository;privatefinal PricingService pricingService;publicProductService(@NotNull ProductRepository productRepository,@NotNull PricingService pricingService) {this.productRepository = productRepository;this.pricingService = pricingService;}@NonNullpublic Product createProduct(@Valid @NotNull ProductDTO productDTO) {Productproduct=newProduct(productDTO.getName(), productDTO.getDescription());product.setPrice(pricingService.calculateInitialPrice(productDTO.getCategory()));return productRepository.save(product);}@NonNullpublic Optional<Product> getProductById(@NonNull Long id) {return productRepository.findById(id);}publicvoidupdateProductStock(@NonNull Long id, @NotNull Integer quantity) {productRepository.findById(id).ifPresent(product -> {product.setStockQuantity(quantity);productRepository.save(product);});}@NonNullpublic List<Product> searchProducts(@NonNull String keyword) {return productRepository.searchByNameOrDescription(keyword);}
}publicclassProductDTO {@NotNullprivate String name;@NotNullprivate String description;@NotNullprivate String category;// getters and setters
}publicclassProduct {private Long id;private String name;private String description;private Double price;private Integer stockQuantity;// constructor, getters, and setters
}

代码解析

  1. 1. 构造函数参数

    public ProductService(@NotNull ProductRepository productRepository,@NotNull PricingService pricingService)
    @NotNull 确保 Spring 的依赖注入提供非 null 的依赖项。在 bean 创建期间发生运行时验证。
  2. 2. 方法返回类型

    @NonNull
    public Product createProduct(@Valid @NotNull ProductDTO productDTO)
    返回类型上的 @NonNull 向调用者表明此方法永远不会返回 null。静态分析工具可以警告潜在的 null 解引用。
  3. 3. 方法参数

    public void updateProductStock(@NonNull Long id, @NotNull Integer quantity)
    id 上的 @NonNull 用于静态分析。quantity 上的 @NotNull 将在运行时验证。
  4. 4. DTO 字段

    public class ProductDTO {@NotNullprivate String name;// ...
    }
    DTO 字段上的 @NotNull 确保在使用 @Valid 时对其进行验证。
  5. 5. Optional 的使用

    @NonNull
    public Optional<Product> getProductById(@NonNull Long id)
    返回 Optional<Product> 是 Java 8+ 处理潜在缺失值的方法。Optional 返回类型上的 @NonNull 确保 Optional 本身永远不为 null。

最佳实践和专业提示

  • • 一致使用:在 DTO 和实体中,在所有非 null 字段和参数上一致应用 @NotNull

  • • 验证组:使用 Jakarta Bean Validation 组在不同上下文中应用不同的验证规则。

  • • 自定义约束:为复杂的验证规则创建自定义约束注解。

  • • IDE 中的 Null 分析:配置您的 IDE(例如,IntelliJ IDEA)以遵循 Spring 的 null 安全注解。

  • • 测试:编写单元测试以验证 @NotNull 约束是否强制执行。

  • • 文档:在公共 API 中使用 @NonNull,以清晰地向其他开发人员传达 null 安全约定。

  • • 性能考虑:注意关键路径中过度运行时验证的性能影响。

  • • 与其他注解结合使用:将 @NotNull 与其他约束(如 @Size 或 @Pattern)结合使用,以进行全面验证。

高级场景

  • • 泛型方法中的 Null 安全

  • • 响应式编程中的 Null 安全

  • • 接口中 Null 性的处理

// 泛型方法中的 Null 安全
@NonNull
public <T> List<T> processItems(@NonNull List<@NotNull T> items) {// 处理逻辑
}// 响应式编程中的 Null 安全
@NonNull
public Mono<Product> reactiveCreateProduct(@Valid @NotNull ProductDTO productDTO) {// 响应式创建逻辑
}// 接口中 Null 性的处理
publicinterfaceUserService {@NonNull User findUser(@NonNull String username);
}

为什么在接口中使用 @NonNull?

在我们的接口示例中,我们使用了来自 Spring Framework 的 @NonNull(org.springframework.lang.NonNull),而不是来自 Jakarta Bean Validation 的 @NotNull(jakarta.validation.constraints.NotNull)。这种选择是经过深思熟虑的,基于几个重要因素:

  • • 语义含义@NonNull 主要用于静态分析和文档。它在不强制运行时行为的情况下传达设计意图。

  • • 运行时影响@NotNull 设计用于运行时验证,可能具有性能影响。接口定义约定,而不是实现,因此运行时检查通常不适合此级别。

  • • 框架一致性:Spring Framework 专门为 API 和约定提供了 @NonNull。在基于 Spring 的应用程序中使用 Spring 的注解可以保持一致性。

  • • 编译时检查:许多 IDE 和静态分析工具都认可 @NonNull,以便在开发期间进行 null 安全检查。这有助于在开发过程的早期捕获潜在的 null 相关问题。

结论

掌握 Spring Boot 3.2 与 Jakarta 中的 @NotNull 和 @NonNull 注解对于开发健壮、null 安全的应用程序至关重要。虽然 @NotNull 提供运行时验证,但 @NonNull 增强了静态分析和文档。通过明智地应用这些注解,您可以创建强大的防御机制来抵御空指针异常

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/34789.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开启云服务器ubuntu22.04的远程桌面,支持Windows远程连接 - 开启XRDP支持

效果图 环境 云服务器 Ubuntu 22.04 lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.5 LTS Release: 22.04 Codename: jammy 本地windows10 步骤 前置动作 # 远程登录 ssh rootx.x.x.x# 看看硬盘够不够空间&…

虚拟化数据恢复—重装系统服务器崩了的数据恢复过程

虚拟化数据恢复环境&故障&#xff1a; VMware虚拟化平台 vmfs文件系统 工作人员误操作重装操作系统&#xff0c;服务器崩溃。 重装系统会导致文件系统元文件被覆盖。要恢复数据&#xff0c;必须找到&提取重装系统前的文件系统残留信息&#xff0c;通过提取出来的元文件…

harmonyOS NEXT开发与前端开发深度对比分析

文章目录 1. 技术体系概览1.1 技术栈对比1.2 生态对比 2. 开发范式比较2.1 鸿蒙开发范式2.2 前端开发范式 3. 框架特性对比3.1 鸿蒙 Next 框架特性3.2 前端框架特性 4. 性能优化对比4.1 鸿蒙性能优化4.2 前端性能优化 5. 开发工具对比5.1 鸿蒙开发工具5.2 前端开发工具 6. 学习…

AI智能混剪工具:AnKo打造高效创作的利器!

AI智能混剪工具&#xff1a;AnKo打造高效创作的利器&#xff01; 随着AI技术的迅速发展&#xff0c;AI智能混剪工具逐渐成为内容创作的利器&#xff0c;尤其是AnKo&#xff0c;作为一款免费的AI创作平台&#xff0c;提供了多模型AI聚合工具平台&#xff0c;能为用户带来更高效…

【Hestia Project 数据集】美国化石燃料 CO₂ 排放数据

Hestia Project™ 是一个革命性的研究项目,旨在帮助城市更精确地量化和管理与气候变化相关的碳排放问题。该项目提供了细粒度(建筑、街道、工厂级别)的化石燃料 CO₂ 排放数据,并通过直观的三维可视化系统向公众、政策制定者、科学家和工业界提供详细的时空信息,支持碳管理…

【TCP】三次挥手,四次挥手详解--UDP和TCP协议详解

活动发起人小虚竹 想对你说&#xff1a; 这是一个以写作博客为目的的创作活动&#xff0c;旨在鼓励大学生博主们挖掘自己的创作潜能&#xff0c;展现自己的写作才华。如果你是一位热爱写作的、想要展现自己创作才华的小伙伴&#xff0c;那么&#xff0c;快来参加吧&#xff01…

传感云揭秘:边缘计算的革新力量

在当今快速发展的科技时代&#xff0c;传感云和边缘计算系统正逐渐成为人们关注的焦点。传感云作为物联网与云计算的结合体&#xff0c;通过虚拟化技术将物理节点转化为多个服务节点&#xff0c;为用户提供高效、便捷的服务。而边缘计算则是一种靠近数据源头或物端的网络边缘侧…

Springboot中的 Mapper 无法找到的 可能原因及解决方案

目录 前言1. 问题所示2. 原理分析3. 解决方法前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 1. 问题所示 执行代码的时候,出现如下问题: A component required a bean of type cn.iocoder.yudao.module.gate.dal.mysql.logger.GateOperateLogMap…

【c++】开发环境IDE、常见调试方法(gdb等)、基础c++语法特性、算法OJ刷题、入门c++项目【持续更新】

1 开发环境&IDE 基本就是如下3款,个人使用体验&#xff1a; vscode&#xff1a;优点-轻量化&#xff0c;插件多&#xff0c;便于远程调试&#xff0c;缺点-配置复杂 clion&#xff1a;优点-集成环境&#xff0c;最易于上手&#xff0c;缺点-商业软件&#xff0c;收费 visu…

Leetcode做题记录----3

1474、删除链表M个节点之后的N个节点 思路&#xff1a; 1、两个循环解决问题 第一个循环移动M个位置&#xff0c;第二个循环确定移动N个位置后的&#xff0c;然后将M位置的节点的next指向&#xff0c;N位置后的节点即可 2、注意边界条件和判空处理 代码实现&#xff1a; pub…

pytorch快速入门——手写数字分类GPU加速

&#x1f451;主页&#xff1a;吾名招财 &#x1f453;简介&#xff1a;工科学硕&#xff0c;研究方向机器视觉&#xff0c;爱好较广泛… ​&#x1f4ab;签名&#xff1a;面朝大海&#xff0c;春暖花开&#xff01; pytorch快速入门——手写数字分类GPU加速 一、tensor1&#…

阿里wan2.1本地部署

1.安装虚拟环境&#xff0c; a) 安装python-3.11.8 b)在本地目录运行 - python -m venv Wan2.1-env - cd Scripts - activate 2.下载代码 git clone https://github.com/Wan-Video/Wan2.1.git cd Wan2.1 3.安装依赖库 pip install torch torchvision --index-url https://…

HTTPS建立连接过程

一、混合加密 通过混合加密的方式可以保证信息的机密性&#xff0c;解决了窃听的风险。 HTTPS采用的是对称加密和非对称加密结合的混合加密方式&#xff1a; &#xff08;1&#xff09; 在通信建立前采用非对称加密的方式交换会话密钥&#xff0c;后续就不再使用非对称加密。 &…

Leetcode-2272. Substring With Largest Variance [C++][Java]

目录 一、题目描述 二、解题思路 【C】 【Java】 Leetcode-2272. Substring With Largest Variancehttps://leetcode.com/problems/substring-with-largest-variance/description/2272. 最大波动的子字符串 - 力扣&#xff08;LeetCode&#xff09;2272. 最大波动的子字符串…

蓝桥杯备赛 Day0_移动零

&#x1f388; 个人主页&#x1f449;&#xff1a;tbRNA-CSDN博客tbRNA-CSDN博客tbRNA-CSDN博客 &#x1f4af; 个人简介&#xff1a;在校大学生一枚&#x1f48b;. &#x1f60d; 希望我的文章对大家有着不一样的帮助&#xff0c;欢迎大家关注我&#xff0c;感谢大家的多多支持…

EDAS:投稿经验-word版本-问题解决

1. 字体不对&#xff0c;字体未嵌入问题 问题&#xff1a;word转PDF后&#xff0c;总是显示有字体格式不对&#xff08;忘记截图了&#xff09;。 办法&#xff1a;1. EDAS投稿PDF格式问题-CSDN博客-PDF上修改 IEEE论文检测的字体未嵌入问题Times New Ro…

TCP/IP协议中三次握手(Three-way Handshake)与四次挥手(Four-way Wave)

TCP/IP协议中三次握手&#xff08;Three-way Handshake&#xff09;与四次挥手&#xff08;Four-way Wave&#xff09; 一、TCP三次握手&#xff08;Three-way Handshake&#xff09;二、TCP四次挥手&#xff08;Four-way Wave&#xff09;三、常见问题解答总结为什么三次握手不…

代码随想录Day16

Day16 二叉树part06 LeetCode 530.二叉搜索树的最小绝对差 题目描述 给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差值 。 差值是一个正数&#xff0c;其数值等于两值之差的绝对值。 示例 输入&#xff1a;root [4,2,6,1,3] 输出&…

用通义大模型写爬虫程序,汇总各科成绩

需求&#xff1a;根据各科网址&#xff0c;输入学号、姓名查询成绩。 中间反反复复很多次&#xff0c;本文只记下重点的几次和大模型的沟通历史。 输入界面 查询界面 round0&#xff08;最初的问题&#xff09; 请在windows下&#xff0c;使用python的selenium库&#xff0…

Java算法OJ(12)

目录 1.前言 2.正文 2.1Fib数列 2.2单词搜索 2.3杨辉三角 3.小结 1.前言 哈喽大家好吖&#xff0c;今天来分享几道的练习题&#xff0c;欢迎大家在评论区多多交流&#xff0c;废话不多说让我们直接开始吧。 2.正文 2.1Fib数列 题目&#xff1a;斐波那契数列_牛客题霸…