Java架构师教你编码规范-如何校验参数?

简介: Java架构师教你编码规范-如何校验参数?

1 参数校验的意义

大多数方法对传递给它们的参数值有限制。例如,索引值必须非负,对象引用必须非空。

  • 应该清楚地在文档中记录所有这些限制,并在方法主体的开头使用检查来实施它们。
  • 应该在错误发生后尽快找到它们,这是一般原则。如果不这样做,就不太可能检测到错误,而且即使检测到错误,确定错误的来源也很难。

若一个无效参数被传递给一个方法

  • 若该方法在执行前检查参数,这过程将迅速失败,并引发异常
  • 若方法未检查参数,可能会在处理过程中出现:

    • 莫名其妙的异常而失败
    • 正常返回,但会悄悄计算错误结果
    • 正常返回,但会使某对象处于隐患状态,可能在未来某不确定时间在某不相关代码点报错。

总之,若无验证参数,可能会违反失败原子性。

对public、protected方法,要在方法说明使用 Javadoc 的 @throws 标签说明如果违反参数值限制时会抛出的异常。通常为 IllegalArgumentExceptionIndexOutOfBoundsExceptionNullPointerException。一旦在文档中记录了方法参数上的限制,并且记录违反这些限制将引发的异常,强加这些限制就很简单了。

  • 看案例:

文档注释并没说「若 m 为空,mod 将抛NPE」,尽管方法确实这么做了,作为调用 m.signum() 的副产物。该异常记录在外围 BigInterger 类级别的文档注释。类级别注释适用于类的所有public方法中的所有参数。这可以避免在每个方法上分别记录每个 NullPointerException 而造成混乱。
它可与 @Nullable 或类似注解结合使用,以指示某特定参数可能为 null,但这种做法并不标准,而且使用了多个注解。

2 最佳实践

Java 7 提供 Objects.requireNonNull 不再需手动执行空检查。

如果愿意,还可自定义异常详情。该方法返回其输入,所以使用一个值的同时可执行判空:

// 内置 Java 的判空功能
this.strategy = Objects.requireNonNull(strategy, "strategy");

也可以忽略返回值并使用 Objects.requireNonNull 作为一个独立判空方法。

3 边界检查

在 Java 9 中,边界检查功能被添加到 java.util.Objects。该功能由三个方法组成:

  • checkFromIndexSize
  • checkFromToIndex
  • checkIndex

该套工具不如判空方法灵活。它不允许自定义异常详细信息,仅适用于 List 和数组索引。它不处理封闭范围(包含两个端点)。

4 断言

对于未暴露的方法,作为包作者,你应该控制方法在何时能被调用,因此你可以并且也应该确保只传入有效参数值。因此,非public方法可使用断言检查入参:

从本质上说,这些断言是在声称被断言的条件为 true,而不管客户端如何调用。与普通校验不同的是:

  • 若断言失败,会抛 AssertionError
  • 若断言没有作用,本质上不存在成本,除非通过将 -ea( 或 -enableassertion)标识传递给 java 命令来启用它们

尤其应检查那些尚未由方法调用,而是存起供日后使用的参数的有效性。例如静态工厂方法,它接受 int 数组并返回数组的 List 视图。若客户端传入 null,将抛 NullPointerException,因为该方法具有显式检查(调用 Objects.requireNonNull)。如果省略检查,该将返回对新创建的 List 实例的引用,该实例将在客户端试图使用它时抛出 NullPointerException。到那时,List 实例的起源很难确定,使调试变得复杂。
构造器就是一种特殊情况。务必检查构造器入参有效性,避免构造生成实例对象时,违背对象的不变性。

在执行方法前,应显式检查参数,也有例外 - 有效性检查成本较高或不切实际,或检查在计算过程中隐式执行了。
例如,一个为对象 List 排序的方法,比如 Collections.sort(List)。List 中的所有对象必须相互比较。在对 List 排序的过程中,List 中的每个对象都会与列表中的其他对象进行比较。如果对象不能相互比较,将抛出 ClassCastException,这正是 sort 方法应该做的。因此,没有必要预先检查列表中的元素是否具有可比性。但不加区别地依赖隐式有效性检查可能导致失败原子性的丢失。

有时,计算任务会隐式地执行所需的有效性检查,但如果检查失败,则抛出错误的异常。即计算任务由于无效参数值所抛异常,与文档中记录的方法要抛出的异常不匹配。此时应该使用异常转换将计算任务抛出的异常转换为正确的异常。

5 总结

请勿从本规范推得:对参数的任意限制都是好事。相反的,应该把方法设计得既通用又实用。对参数施加的限制越少越好,假设该方法可对它所接受的所有参数值进行合理的处理。然而,一些限制常常是实现抽象的内在限制。

每次编写方法或构造器时,都应考虑参数存在哪些限制。你应该在文档中记录这些限制,并在方法主体的开头显式检查。养成这样的习惯!这一少量工作将在有效性检查出现第一次失败时连本带利地偿还给你!

目录
相关文章
|
5天前
|
SQL Java 数据库连接
如何用 Java 校验 SQL 语句的合法性?
本文介绍了五种校验 SQL 语句合法性的方案:1) 使用 JDBC API 的 `execute()` 方法,通过捕获异常判断合法性;2) 使用 JSqlParser 库解析 SQL 语句为 Java 对象;3) 使用正则表达式检查 SQL 语句格式;4) 使用 ANTLR 生成 SQL 解析器;5) 使用 Apache Calcite 解析 SQL。每种方法各有优劣,具体选择取决于需求和个人偏好。需要注意的是,这些方法仅能校验语法合法性,无法保证语义正确性,仍需防范 SQL 注入攻击。
|
1月前
|
SQL 存储 关系型数据库
MySQL进阶突击系列(01)一条简单SQL搞懂MySQL架构原理 | 含实用命令参数集
本文从MySQL的架构原理出发,详细介绍其SQL查询的全过程,涵盖客户端发起SQL查询、服务端SQL接口、解析器、优化器、存储引擎及日志数据等内容。同时提供了MySQL常用的管理命令参数集,帮助读者深入了解MySQL的技术细节和优化方法。
|
2月前
|
机器学习/深度学习 自然语言处理 物联网
NeurIPS 2024 Oral:小参数,大作为!揭秘非对称 LoRA 架构的高效性能
近期,一篇题为《\model~: 非对称LoRA架构实现高效微调》的论文被NeurIPS 2024接收为口头报告,该研究提出了一种创新的非对称LoRA架构,旨在解决大型语言模型(LLMs)在保持高性能的同时提高训练和部署效率的问题。通过引入共享A矩阵和多个B矩阵,\model~不仅提高了参数效率,还在多个数据集上展示了超越现有PEFT方法的性能,尤其是在多任务域和复杂数据集上的表现尤为突出。此架构还有效减少了训练能耗和延迟,为LLMs的高效应用提供了新思路。
51 4
|
2月前
|
Java
实现java执行kettle并传参数
实现java执行kettle并传参数
38 1
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
Tokenformer:基于参数标记化的高效可扩展Transformer架构
本文是对发表于arXiv的论文 "TOKENFORMER: RETHINKING TRANSFORMER SCALING WITH TOKENIZED MODEL PARAMETERS" 的深入解读与扩展分析。主要探讨了一种革新性的Transformer架构设计方案,该方案通过参数标记化实现了模型的高效扩展和计算优化。
253 0
|
4月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
514 37
|
2月前
|
Java
在Java中定义一个不做事且没有参数的构造方法的作用
Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。
|
3月前
|
存储 算法 Java
java制作海报六:Graphics2D的RenderingHints方法参数详解,包括解决文字不清晰,抗锯齿问题
这篇文章是关于如何在Java中使用Graphics2D的RenderingHints方法来提高海报制作的图像质量和文字清晰度,包括抗锯齿和解决文字不清晰问题的技术详解。
116 0
java制作海报六:Graphics2D的RenderingHints方法参数详解,包括解决文字不清晰,抗锯齿问题
|
3月前
|
Java
java构造方法时对象初始化,实例化,参数赋值
java构造方法时对象初始化,实例化,参数赋值
109 1
|
4月前
|
设计模式 架构师 Java
Java开发工程师转架构师需要学习什么
Java开发工程师转型为架构师需掌握多项技能:精通Java及框架、数据库与分布式系统;熟悉设计模式与架构模式;积累项目经验;提升沟通与领导力;持续学习新技术;培养系统设计与抽象能力;了解中间件及开发工具;并注重个人特质与职业发展。具体路径应结合个人目标与实际情况制定。
90 19