Java代码规范

news2024/9/25 11:09:36

前言

由于近年来对于代码质量的要求越来越高,特制定部门级Java代码规范规则集X-JAVA-RULE,整体要求规则可用可查、循序渐进。

可用是指考虑目前已有代码的体量,不满足这些规则的代码能否能被修复,如果工作量巨大不能被修复或者实际适用场景不会导致漏洞,暂时没有必要纳入其中。

比如规则【包名统一使用小写】是个很好的规则,但是考虑到老项目中有大量的代码在大小的包名下面,这里没有纳入规则集X-JAVA-RULE中。

可查是指有工具可以扫描出,而不是人工筛查。在规则后面附上了SonaQube中的相应规则名称。要求在SonaQube可查询对应规则。

比如规则1
在这里插入图片描述

在这里插入图片描述

循序渐进是指以下规则集不是最终版本,根据实际情况后续会不断扩展。规则集会增删,会被继承,但每次不建议加入过多规则,导致无法推进。
比如【包名统一使用小写】可以考虑在后续新项目中加入,此时新建一个继承【X-JAVA-RULE】的规则集【X-JAVA-RULE-EXT】,将这些规则集纳入其中。

以下规则内容完全参考 阿里巴巴Java开发手册《嵩山版》阿里巴巴 Java 开发手册 终极版(1.3.0),二者有出入则参考后者。比如规则14,在两个版本中不一致。

在《嵩山版》中
在这里插入图片描述
在终极版中
在这里插入图片描述
此处以终极版为准。

规则集X-JAVA-RULE

1. 【强制】 代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。

反例: _name / _name / $Object / name / name$ / Object$

[p3c]All names should not start or end with an underline or a dollar sign.

2. 【强制】 类名使用 UpperCamelCase 风格,但以下情形例外: DO / BO / DTO / VO / AO /PO / UID 等。

正例: ForceCode / UserDO / HtmlDTO / XmlService / TcpUdpDeal / TaPromotion

反例: forcecode / UserDo / HTMLDto / XMLService / TCPUDPDeal / TAPromotion

[p3c]Class names should be nouns in UpperCamelCase except domain models: DO, BO, DTO, VO, etc.

3. 【强制】方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰形式。

正例: localValue / getHttpMessage() / inputUserId

[p3c]Method names, parameter names, member variable names, and local variable names should be written in lowerCamelCase.

4. 【强制】 POJO 类中布尔类型的变量,都不要加 is,否则部分框架解析会引起序列化错误。

反例: 定义为基本数据类型 Boolean isDeleted; 的属性,它的方法也是 isDeleted(), RPC 框架在反向解析的时候, “以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常。

[p3c]Do not add ‘is’ as prefix while defining Boolean variable.

5. 【强制】 long 或者 Long 初始赋值时, 使用大写的 L,不能是小写的 l,小写容易跟数字 1 混淆,造成误解。

说明: Long a = 2l; 写的是数字的 21,还是 Long 型的 2?

[p3c]‘L’ instead of ‘l’ should be used for long or Long variable.

6. 【强制】创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。

正例

public class TimerTaskThread extends Thread {
  public TimerTaskThread() {
    super.setName("TimerTaskThread");
        ...
}

[p3c]A meaningful thread name is helpful to trace the error information,so assign a name when creating threads or thread pools.

7. 【强制】 必须回收自定义的 ThreadLocal 变量,尤其在线程池场景下,线程经常会被复用,如果不清理自定义的 ThreadLocal 变量,可能会影响后续业务逻辑和造成内存泄露等问题。尽量在代理中使用 try-finally 块进行回收。

正例:

objectThreadLocal.set(userInfo);
try {
    // ...
} finally {
    objectThreadLocal.remove();
}

[p3c]type ‘ThreadLocal’ must call remove() method at least one times.

8. 【强制】 Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用equals。

说明: 推荐使用 java.util.Objects#equals(JDK7 引入的工具类)

正例: “test”.equals(object);

反例: object.equals(“test”);

[p3c]Equals should be invoked by a constant or an object that is definitely not null.

9. 【强制】所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。

说明: 对于 Integer var = ? 在-128 至 127 范围内的赋值, Integer 对象是在 IntegerCache.cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。

[p3c]The wrapper classes should be compared by equals method rather than by symbol of ‘==’ directly.

[p3c]To judge the equivalence of floating-point numbers, == cannot be used for primitive types, while equals cannot be used for wrapper classes.

10. 关于基本数据类型与包装数据类型的使用标准如下:

1) 【强制】 所有的 POJO 类属性必须使用包装数据类型。

2) 【强制】 RPC 方法的返回值和参数必须使用包装数据类型。

3) 【推荐】 所有的局部变量使用基本数据类型。

说明: POJO 类属性没有初值是提醒使用者在需要使用时,必须自己显式地进行赋值,任何NPE 问题,或者入库检查,都由使用者来保证。

正例: 数据库的查询结果可能是 null,因为自动拆箱,用基本数据类型接收有 NPE 风险。

反例: 比如显示成交总额涨跌情况,即正负 x%, x 为基本数据类型,调用的 RPC 服务,调用不成功时,返回的是默认值,页面显示为 0%,这是不合理的,应该显示成中划线。所以包装数据类型的 null 值,能够表示额外的信息,如:远程调用失败,异常退出 。

[p3c]Rules for using primitive data types and wrapper classes.

11. 【强制】 关于 hashCode 和 equals 的处理,遵循如下规则:

1) 只要重写 equals,就必须重写 hashCode。 “equals(Object obj)” and “hashCode()” should be overridden in pairs

2) 因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的对象必须重写这两个方法。

3) 如果自定义对象做为 Map 的键,那么必须重写 hashCode 和 equals。

说明: String 重写了 hashCode 和 equals 方法,所以我们可以非常愉快地使用 String 对象作为 key 来使用。

Correctness - Use of class without a hashCode() method in a hashed data structure

12. 【强制】 ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException异常, 即java.util.RandomAccessSubList cannot be cast to java.util.ArrayList.

说明: subList 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList ,而是ArrayList 的一个视图,对于 SubList 子列表的所有操作最终会反映到原列表上。

[p3c]Do not cast subList in class ArrayList, otherwise ClassCastException will be thrown.

13. 【强制】在 subList 场景中, 高度注意对原集合元素个数的修改,会导致子列表的遍历、增加、删除均会产生 ConcurrentModificationException 异常。

[p3c]When using subList, be careful to modify the size of original list.

14. 【强制】使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一样的数组,大小就是 list.size()。

说明: 使用 toArray 带参方法,入参分配的数组空间不够大时, toArray 方法内部将重新分配内存空间,并返回新数组地址; 如果数组元素大于实际所需,下标为[ list.size() ]的数组元素将被置为 null,其它数组元素保持原值,因此最好将方法入参数组大小定义与集合元素个数一致。

正例:

List<String> list = new ArrayList<String>(2);
list.add("guan");
list.add("bao");
String[] array = new String[list.size()];
array = list.toArray(array)

反例: 直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它类型数组将出现 ClassCastException 错误。

[p3c]Do not use toArray method without arguments.

15. 【强制】使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的 add/remove/clear 方法会抛出UnsupportedOperationException 异常。

说明: asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。 Arrays.asList体现的是适配器模式,只是转换接口,后台的数据仍是数组。

String[] str = new String[] { "you", "wu" };
List list = Arrays.asList(str);

第一种情况: list.add(“yangguanbao”); 运行时异常。
第二种情况: str[0] = “gujin”; 那么 list.get(0)也会随之修改。

[p3c]Do not use methods which will modify the list after using Arrays.asList to convert array to list.

16. 【强制】不要在 foreach 循环里进行元素的 remove/add 操作。 remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。

正例:

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
 String item = iterator.next();
 if (删除元素的条件) {
     iterator.remove();
 }
}

反例:

List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
for (String item : list) {
 if ("1".equals(item)) {
     list.remove(item);
 }
}

说明: 以上代码的执行结果肯定会出乎大家的意料,那么试一下把“1”换成“2”,会是同样的结果吗?

[p3c]Do not remove or add elements to a collection in a foreach loop.

17. 【强制】 SimpleDateFormat 是线程不安全的类,一般不要定义为 static 变量,如果定义为static,必须加锁,或者使用 DateUtils 工具类。

正例: 注意线程安全,使用 DateUtils。亦推荐如下处理:

private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
 @Override
 protected DateFormat initialValue() {
     return new SimpleDateFormat("yyyy-MM-dd");
 }
};

说明: 如果是 JDK8 的应用,可以使用 Instant 代替 Date, LocalDateTime 代替 Calendar,DateTimeFormatter 代替 SimpleDateFormat,官方给出的解释: simple beautiful strong immutable thread-safe。

[p3c]SimpleDataFormat is unsafe, do not define it as a static variable. If have to, lock or DateUtils class must be used.

18. 【强制】多线程并行处理定时任务时, Timer 运行多个 TimeTask 时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用 ScheduledExecutorService 则没有这个问题。

[p3c]Use ScheduledExecutorService instead.

19. 【强制】在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度。

说明: 不要在方法体内定义: Pattern pattern = Pattern.compile(规则);

[p3c]When using regex, precompile needs to be done in order to increase the matching performance.

20. 【强制】不能在 finally 块中使用 return, finally 块中的 return 返回后方法结束执行,不会再执行 try 块中的 return 语句。

[p3c]Never use return within a finally block.

21. 【强制】 日期格式化时,传入 pattern 中表示年份统一使用小写的 y。

说明: 日期格式化时, yyyy 表示当天所在的年,而大写的 YYYY 代表是 week in which year( JDK7 之后引入的概念),意思是当天所在的周属于的年份,一周从周日开始,周六结束,只要本周跨年,返回的 YYYY就是下一年。

正例: 表示日期和时间的格式如下所示:

new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") 

[p3c]Date format string [%s] is error,When doing date formatting, ‘y’ should be written in lowercase for ‘year’.

22. 【强制】 禁止使用构造方法 BigDecimal(double)的方式把 double 值转化为 BigDecimal 对象。

说明: BigDecimal(double)存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。如: BigDecimal g = new BigDecimal(0.1F); 实际的存储值为: 0.10000000149

正例: 优先推荐入参为 String 的构造方法,或使用 BigDecimal 的 valueOf 方法,此方法内部其实执行了Double 的 toString,而 Double 的 toString 按 double 的实际能表达的精度对尾数进行了截断。

BigDecimal recommend1 = new BigDecimal("0.1");
BigDecimal recommend2 = BigDecimal.valueOf(0.1); 

[p3c]Avoid using the constructor BigDecimal(double) to convert double value to a BigDecimal object.

23. 【强制】 如上所示 BigDecimal 的等值比较应使用 compareTo()方法,而不是 equals()方法。

说明: equals()方法会比较值和精度( 1.0 与 1.00 返回结果为 false) , 而 compareTo()则会忽略精度。

Correctness - Method calls BigDecimal.equals()

24. 【强制】 判断所有集合内部的元素是否为空,使用 isEmpty()方法,而不是 size()==0 的方式。

说明: 在某些集合中,前者的时间复杂度为 O(1),而且可读性更好。

Map<String, Object> map = new HashMap<>(16);
if(map.isEmpty()) {
	System.out.println("no element in this map.");
}

Collection.isEmpty() should be used to test for emptiness

25. 【强制】 在使用阻塞等待获取锁的方式中,必须在 try 代码块之外,并且在加锁方法与 try 代码块之间没有任何可能抛出异常的方法调用,避免加锁成功后,在 finally 中无法解锁。

说明一: 如果在 lock 方法与 try 代码块之间的方法调用抛出异常,那么无法解锁,造成其它线程无法成功获取锁。
说明二: 如果 lock 方法在 try 代码块之内,可能由于其它方法抛出异常,导致在 finally 代码块中, unlock对未加锁的对象解锁,它会调用 AQS 的 tryRelease 方法(取决于具体实现类),抛出IllegalMonitorStateException 异常。
说明三: 在 Lock 对象的 lock 方法实现中可能抛出 unchecked 异常,产生的后果与说明二相同。

正例:

Lock lock = new XxxLock();
// ...
lock.lock();
try {
	doSomething();
	doOthers();
} finally {
	lock.unlock();
}

反例:

Lock lock = new XxxLock();
// ...

try {
	// 如果此处抛出异常,则直接执行 finally 代码块
	doSomething();
	// 无论加锁是否成功, finally 代码块都会执行
	lock.lock();
	doOthers();
} finally {
	lock.unlock();
} 

[p3c]Lock operation [%s] must immediately follow by try block, and unlock operation must be placed in the first line of finally block.

26. 【强制】 在一个 switch 块内,每个 case 要么通过 continue/break/return 等来终止,要么注释说明程序将继续执行到哪一个 case 为止;在一个 switch 块内,都必须包含一个 default 语句并且放在最后,即使它什么代码也没有。

说明: 注意 break 是退出 switch 语句块,而 return 是退出方法体。

行 finally 代码块

{
	doSomething();
	// 无论加锁是否成功, finally 代码块都会执行
	lock.lock();
	doOthers();
} finally {
	lock.unlock();
} 

[p3c]Lock operation [%s] must immediately follow by try block, and unlock operation must be placed in the first line of finally block.

27. 【强制】 在一个 switch 块内,每个 case 要么通过 continue/break/return 等来终止,要么注释说明程序将继续执行到哪一个 case 为止;在一个 switch 块内,都必须包含一个 default 语句并且放在最后,即使它什么代码也没有。

说明: 注意 break 是退出 switch 语句块,而 return 是退出方法体。

[p3c]In a switch block, each case should be finished by break/return.

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小程序和Vue+uniapp+unicloud培训课件

文章目录**一、什么是小程序****1.1** **小程序简介****1.2** **小程序的特点****1.3** **小程序的开发流程**个人小程序和企业小程序的区别1.4 小程序代码构成1.4.1 JSON 配置1.4.2 WXML 模板**数据绑定**逻辑语法条件逻辑列表渲染模板引用共同属性1.4.3 WXSS 样式1.4.4 JS 逻…

9. IP组播(理论)

作为IP传输三种方式之一&#xff0c;IP组播通信指的是IP报文从一个源发出&#xff0c;被转发到一组特定的接收者。相较于传统的单播和广播&#xff0c;IP组播可以有效地节约网络带宽、降低网络负载&#xff0c;所以被广泛应用于IPTV、实时数据传送和多媒体会议等网络业务中。 …

5 逻辑回归及Python实现

1 主要思想 分类就是分割数据&#xff1a; 两个条件属性&#xff1a;直线&#xff1b;三个条件属性&#xff1a;平面&#xff1b;更多条件属性&#xff1a;超平面。 使用数据&#xff1a; 5.1,3.5,0 4.9,3,0 4.7,3.2,0 4.6,3.1,0 5,3.6,0 5.4,3.9,0 . . . 6.2,2.9,1 5.1,2.5…

一个容易被忽视的标签 —— iframe

前言 甲问&#xff1a;说说你知道的HTML标签。 乙于是说了一大堆标签&#xff0c;比如div&#xff0c;span等等。 甲说&#xff1a;那你知道 iframe 标签吗&#xff1f; 乙这时候迟疑了片刻&#xff0c;缓缓说出&#xff1a;知道它&#xff0c;但是不太了解这个标签。 HTM…

学到了,原来华为是这样判断MES系统的好坏的

可以想象华为公司对供应商的要求是多么严格&#xff0c;那么我们今天来谈一下华为对供应商工厂MES系统这块的要求&#xff0c;这要从生产防错系统、品质管控系统、品质追溯系统、出货防错系统四个方面来说。一、生产物料和生产治具防错系统建立完整的物料和治具标签方案&#x…

常用的数据脱敏(手机、邮箱、身份证号)

一、什么是数据脱敏 先来看看什么是数据脱敏&#xff1f;数据脱敏也叫数据的去隐私化&#xff0c;在我们给定脱敏规则和策略的情况下&#xff0c;对敏感数据比如 手机号、银行卡号 等信息&#xff0c;进行转换或者修改的一种技术手段&#xff0c;防止敏感数据直接在不可靠的环境…

AcWing3485. 最大异或和

先看题目&#xff1a; 说实话&#xff0c;我看到这道题就想用滑动窗口&#xff0c;但是滑了一下发现不太对啊&#xff0c;如果我用滑动窗口的话&#xff0c;那么最后肯定是一个固定长度为m的窗口在持续计算&#xff0c;区间长度小于m的区间的异或和肯定会被遗漏。然后我就想怎么…

vue前端架构说明书模板示例

目录 1. 技术说明... 2 1.1 版本明细... 2 1.2 核心技术介绍... 2 2. 项目结构说明... 3 3. 自动化部署设置说明... 5 4. 打包及运行说明... 5 5. 导包说明... 6 5.1 方案一... 6 5.2 方案二... 7 5.3 补充说明... 7 6. 修改本地运行时链接的服务器说明... 7 7. 常…

从 B 站出发,用 Chrome devTools performance 分析页面如何渲染

页面是如何渲染的&#xff1f;通常会得到“解析 HTML、css 合成 Render Tree&#xff0c;就可以渲染了”的回答。但是具体都做了些什么&#xff0c;却很少有人细说&#xff0c;我们今天就从 Chrome 的性能工具开始&#xff0c;具体看看一个页面是如何进行渲染的&#xff0c;以及…

视频传输协议详解(RTMP、RTSP、HLS)

RTMP——Real Time Messaging Protocol&#xff08;实时消息传输协议&#xff09;RTMP是由Adobe公司提出的&#xff0c;在互联网TCP/IP五层体系结构中应用层&#xff0c;RTMP协议是基于TCP协议的&#xff0c;也就是说RTMP实际上是使用TCP作为传输协议。TCP协议在处在传输层&…

sql学习一

文章目录一、if 语句二、去重问题三、concat,upper,lower四、group_concat五、like 模糊匹配六、union和union all七、流程控制语句case八、limit一、if 语句 if(expr1, expr2, expr3)当expr1的值为真时函数的返回值为expr2&#xff0c;当expr1的值为假时&#xff0c;函数的返…

安装redis并设置开机自启动允许远程链接

一、进入/usr/local目录下面&#xff1b;下载redis包wget https://download.redis.io/releases/redis-5.0.14.tar.gz二、安装gccyum install gcc-c三、解压、进入目录、编译tar -xvf redis-5.0.14.tar.gzcd redis-5.0.14make ##如果报错zmalloc.h:50:31: 致命错误&#xff1a;j…

打破单片机开发模式--胶水语言(JavaScript)

概述 传统的嵌入式单片机开发基本上形式如下图&#xff1a; 该流程对于功能单一或者功能变更极少的场景是比较友好的&#xff0c;但是对于设备应用层变更比较多或者公板方案开发应用的场景&#xff0c;上述场景显的有些累赘。那么有什么方式可以解决呢&#xff1f;&#xff1f…

U-Boot 之七 详解 Driver Model 架构、配置、命令、初始化流程

U-Boot 在 2014 年 4 月参考 Linux Kernel 的驱动模型设计并引入了自己的 Driver Model&#xff08;官方简称 DM&#xff09; 驱动架构。这个驱动模型&#xff08;DM&#xff09;为驱动的定义和访问接口提供了统一的方法&#xff0c;提高了驱动之间的兼容性以及访问的标准性。 …

和月薪3W的聊过后,才知道自己一直在打杂...

前几天和一个朋友聊面试&#xff0c;他说上个月同时拿到了腾讯和阿里的offer&#xff0c;最后选择了阿里。 我了解了下他的面试过程&#xff0c;就一点&#xff0c;不管是阿里还是腾讯的面试&#xff0c;这个级别的程序员&#xff0c;都会考察项目管理能力&#xff0c;并且权重…

[牛客网] HJ35 蛇形矩阵(写了好久才写出来)

链接https://www.nowcoder.com/practice/649b210ef44446e3b1cd1be6fa4cab5e?tpId37&tqId21258&rp1&ru/exam/oj/ta&qru/exam/oj/ta&sourceUrl%2Fexam%2Foj%2Fta%3Fdifficulty%3D2%26page%3D1%26pageSize%3D50%26search%3D%26tpId%3D37%26type%3D37&dif…

区块链行业遭供应链攻击,上万加密钱包被“抄底”损失上亿美元

当地时间8月2日晚间&#xff0c; 区块链行业遭遇了一次行业重创 。据科技媒体TechCrunch报道&#xff0c; 若干名攻击者“抄底”了上万个加密钱包&#xff0c;钱包内有价值上亿美元的代币。 据了解遭受攻击的加密钱包包括Phantom、Slope和TrustWallet等。涉及到的币种除了SOL、…

Vue2的tsx开发入门完全指南

本篇文章尽量不遗漏重要环节&#xff0c;本着真正分享的心态&#xff0c;不做标题党 下面进入正题&#xff1a; 由于现在vue的官方脚手架已经非常完善我们就不单独配置webpack了&#xff0c;节省大量的时间成本。 首先使用vue/cli创建一个vue模版项目&#xff08;记得是vue/…

Dockerfile详解

一、能干嘛&#xff1f; 我们总会遇到下面这种情况&#xff1a;使用docker pull 拉取下来的镜像发现其提供的功能并不完善&#xff0c;比如拉下来个centos的镜像&#xff0c;运行该镜像生成容器发现连vim&#xff0c;ifconfig命令都没有&#xff01;想要在该镜像的基础上扩充其…

[SQL]增删查改语法概览

数据定义 基本概念 基本表 本身独立存在的表SQL中一个关系就对应一个基本表一个(或多个)基本表对应一个存储文件一个表可以带若干索引 存储文件 物理结构对用户透明索引存放在存储文件中 视图 从一个或几个基本表导出的表数据库中至存放数据的定义而不存放视图对应的数据视…