Java编程规范

现代软件架构的复杂性要求需要多人或多团队协同完成开发。在这种背景下,如何高效地协同完成软件的开发呢?对软件工程来说,编程规范是在编程层面对软件开发者的规范或标准。对软件来说,适当的规范和标准绝不是为了消除代码内容的创造性、优雅性,而是限制过度个性化,并以一种普遍认可的统一方式一起做事,提升协作效率,降低沟通成本。代码的字里行间流淌的是软件系统的血液,质量的提升是尽可能少踩坑,杜绝踩重复的坑,切实提升系统稳定性,码出质量。
接下来将从多个方面介绍Java编程规范。如命名风格、注释风格、代码排版风格、变量规范、类型规范、方法规范、接口规范、异常规范、日志规范、其他等。

命名风格

好的命名风格可以让代码更容易理解、维护、使用。编码先从命名风格上进行培养。

【强制】文件编码格式必须是UTF-8

在新增或修改文件时,文件的编码格式必须统一。编程领域,文件编码格式必须是UTF-8,不应为了个人方便使用其他编码格式,
如GBK、ASCII等。

【强制】空白字符只能是空格,不能使用制表符

禁止使用制表符。不同操作系统对制表符的转码不同。不建议使用Tab缩进。如果使用 Tab 缩进,必须设置 1 个 Tab 为 4 个空格。

【强制】标识符仅能使用字母、数字、下划线,且不能以下划线开头

这个规范是Java语言标识符定义规则。建议控制标识符长度不超过31个。如果太长,则需考虑换种角度定义标识符。

【强制】禁止使用拼音与英文混合方式命名或直接使用中文的方式命名

基于英文编码已是事实标准。在定义标识符时,不应将拼音与英文混合或直接使用中文。对国际通用的拼音,可以视同为英文,如BeiJing等。

【强制】禁止使用任何语言的种族歧视性词语

随着种族意识的弱化,不应使用使用种族歧视性词语。如不应使用 blackList/whiteList/slave,而应使用blockList/allowList/secondary等。

【强制】标识符定义风格限制在PascalCase、CamelCase、SnakeCase

标识符定义风格主要有PascalCase、CamelCase、SnakeCase三类。PascalCase也称UpperCamelCase,CamelCase默认指lowerCamelCase。针对缩写、包名、
接口、类、注解、枚举类型、非常量字段、方法、方法参数、局部变量、静态常量、枚举值、泛型、异常等,其命名应遵从不同的风格。
具体要求如下表所示。

类型风格示例
缩写全小写如dto、tcp、html、do。注意,不同厂商对其规范不同。如ali则要求缩写全大写
包名全小写且不含下划线如github、courage007等。注意,连续的单词简单连接在一起,不能使用下划线,如springboot、modelmvc等
接口、类、注解、枚举类型PascalCase如User、Entity、Readable、@Service、ColorEnum。针对枚举类型,使用Enum后缀标识其是枚举类型 对于测试类,统一使用Test后缀。对于抽象类使用Abstract或Base开头类名。对于异常类,统一使用Exception后缀。枚举类型通常是名称或名词短语。接口名称可以是名称或名称短语,也可以是形容词或形容词短语
成员字段、方法参数、局部变量CamelCase如userName、userId等。对于final修饰的局部变量或成员变量,也应将其作为非常量字段处理
静态常量、枚举值SnakeCase如MAX_COUNT、EXPIRED_TIME、RED、GREEN等。不要使用魔鬼数字,要用有意义的常量替代。
方法名CamelCase如getColor、setValue等。方法名通常是动词或动词短语。常见的模式有:is + 布尔属性值,get + 非布尔属性值,has+名称/形容词,动词、动宾短语。部分允许介词的场景:onCreate、toString等
泛型SnakeCase如E、T、T_INNER等。尽量使用单个字符表示,少数场景下需要使用多个字符表示,且使用下划线分割

【推荐】对使用了设计模式的标识符,在在命名时需体现出具体模式

将设计模式体现在名字中,有利于阅读者快速理解架构设计理念。如UserFactory、LoginProxy等;

注释

注释主要有以下三方面的作用:1.能够反映代码的设计思想和主要功能;2.能够描述业务含义,方便其他程序员了解代码背后的含义;3.提示示例代码,方便调用者使用。对于注意的中英文没有特别要求,对于面向国内开发者或公司内部的项目,其注释推荐使用中文,对于面向国际环境或开源的项目,
其注释推荐使用英文。

【强制】必须遵从Javadoc规范

类、类成员、类方法的注释必须使用Javadoc规范。对于override注解修饰的方法,不要求遵循Javadoc规范。对于测试方法、不强制遵循Javadoc规范。

【强制】文件头注释必须包含版权许可

无论是商业软件,还是开源软件,都应包含版权许可,以说明该软件所有权或可用权。

【强制】所有的类都必须添加创建者和创建日期

新增类文件,必须添加创建者和创建日期。

【强制】不用的代码片段,如import、废弃代码,应删除掉,而不是注释掉

不使用的import应删除,没有被引用的字段、方法应删除。不要在已提交生产环境的代码中保留注释的代码。

【建议】正式商用的代码不应包含TODO/FIXME等注释

通过测试验收的代码或已经商用的代码,不应在代码中包含TODO/FIXME的注释。因为已通过测试的代码或商用的代码,理论上应该将所有已知问题解决,
这也符合墨菲定律

【建议】注释应精简准确

好的命名、代码结构是自解释的,注释力求精简准确、表达到位。避免出现注释的一个极端:过多过滥的注释,代码的逻辑一旦修改,修改注释又是相当大的负担。

代码排版

如果将编程看成创作,那么一个个类文件就是一页页的内容。书籍发版讲究排版,以方便读者阅读,编程同样也需要保证排版。

【强制】避免单文件过长,关键代码不应超过2000行

避免引入上帝类。在编码的过程中,要按照单一职责的原则,合理规划类的功能。对于自动生成的临时代码,则不强制要求。

【强制】一个源文件应按照版权、包名、import、类名的顺序定义

注意,import语句不能使用通配符,应严格指明引入的类。

【建议】import引入的包应按照当前模块、二方件、三方件、JDK的顺序

源文件中引入的对象应根据其类型进行统一,以保证风格统一。

【建议】类或接口应按照静态变量、静态块、实例变量、实例块、构造方法、实例方法顺序声明或定义

其中实例方法又可根据访问权限约定其顺序,如先pulic方法,再protected方法,最后private方法。

【强制】严格使用大括号

按照左括号和右括号,在使用大括号时应保证:
(1) 左大括号前不换行
(2) 左大括号后换行
(3) 右大括号前换行
(4) 右大括号后还有 else 等代码则不换行;表示终止的右大括号后必须换行。
在if、else、switch、for、do和while等语句中,即使程序体为空,也应使用大括号,且使用规则不变。

【强制】左大括号前必须加空格

【强制】if、else、switch、for、do或while等保留字与括号之间必须加空格

【强制】任何运算符的左右两边都应加一个空格

【强制】使用空格进行缩进,每次缩进4个空格

不应使用制表符代替4个空格。如果使用tab缩进,应确保对应4个空格(有些编辑器默认会将tab缩进对应成2个空格,如vs-code)。

【强制】注释的双斜线与注释内容之间有且仅有一个空格

示例如下:

// 这是注释
String testStr = "test";

【强制】每行限长120个字符

一行的内容不应过长,国际上推荐单行限制在120个字符以内。对超过120个字符的行,应换行。换行时,第二行相对第一行应缩进4个空格,
从第三行开始不再继续缩进。

【建议】减少不必要的空行,保持代码紧凑

在编码时,有些同学会使用空行来分隔不同的业务含义。这种场景的推荐做法是拆分方法。

变量规范

【强制】不能用浮点数作为循环因子

Java语言中浮点数不是精确存储,不能用浮点数作为循环因子,否则可能导致无限循环问题。

【强制】精确计算时不要使用float或double

Java语言中浮点数不是精确存储,需要精确计算时,可以使用BigDecimal。

【强制】浮点数相等判断时不能直接使用==或equals

Java语言中浮点数不是精确存储,需要判断相等时,可以先转换成BigDecimal,或在精度允许的情况下,使用差值。

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

new BigDecimal(double)存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。
如:BigDecimal g = new BigDecimal(0.1F); 实际的存储值为:0.10000000149。优先推荐入参为 String 的构造方法,
或使用 BigDecimal 的 valueOf 方法,此方法内部其实执行了 Double 的 toString,而 Double 的 toString 按
double 的实际能表达的精度对尾数进行了截断。

【强制】BigDecimal 的等值比较应使用 compareTo()方法,而不是 equals()方法

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

方法规范

【强制】避免方法过长,尽量控制在80行以内

过长的方法意味着方法功能不单一,过于复杂,或过分拆分细节。大方法不容易维护,应尽量控制方法的长度。

【强制】方法的代码块不宜嵌套过深,不要超过4层

一般来说,方法的时间复杂度要控制在 O ( n 2 ) O(n^2) O(n2)范围内,少数情况下可接受时间复杂度 O ( n 3 ) O(n^3) O(n3)的方法。对应地,方法的嵌套层级
也不应过深。
使用卫语句可以有效地减少if语句相关的嵌套层级。此外,还可以考虑使用Stream来减少嵌套和圈复杂度。

【强制】静态方法应使用类名来调用,而不要使用实例或表达式

使用实例来调用静态方法容易产生混淆,让他人以为是实例上的方法。

【强制】所有的重写方法,必须加@Override注解

当子类重写父类方法或实现接口方法是,需要加上@Override注解。尽管@Override注解不是强制,但是对于商用代码,
必须加上@Override注解,以标识这是一个重写方法。

【强制】不应在方法内部修改入参

如果需要修改入参,可以通过定义局部变量的方式实现,不应直接修改入参。

【建议】方法的参数个数不建议超过5个

在方法重构中有一个规则,方法的参数不应超过5个。对需要超过5个场景,要么选择拆分方法,要么选择将多个参数整合成一个(定义一个对象)。

【建议】对于返回集合的方法,不建议返回null

如果对返回集合的方法返回null,还需在调用方进行判空处理。如果未进行判空,则会导致空指针异常。

类型规范

【强制】构造方法禁止加入业务逻辑,对于初始化逻辑,应单独在init方法中执行

【强制】不要在父类方法中执行可能被子类覆盖的方法

当在父类方法中执行可能被子类覆盖的方法时,会导致构造方法的执行不可预知,加大问题的定位难度。

【强制】重写equals方法时,应同时重写hashCode方法

集合在进行索引时,会优先基于hashCode进行判断(一旦hashCode不同,则认定其不存在)。

接口规范

【建议】接口定义中去掉多余的修饰词

在接口中,字段缺省是public static final),方法缺省是public abstract。无需再次补充这些修饰词。

【建议】推荐使用接口去定义一个常量类

接口中的常量只能是静态常量,使用接口定义常量类,可以减少public static final修饰词的编写(在接口中,字段缺省是public static final)。

异常规范

【强制】异常捕获后,不要用来做流程控制,条件控制

可以吞掉异常,但是不应基于异常进行流程控制,条件控制。异常设计的初衷就是解决程序运行中的各种意外。

【强制】不要通过一个空的catch块吞掉异常

当需要忽略异常时,不要使用空块,至少要打印系统日志,记录异常信息。反例:

try {

} catch(IOException e) {
    // 吞掉了异常,却没有记录异常,导致无法定位问题
}

【强制】不要在finally块中使用return、break或continue

try 块中的 return 语句执行成功后,并不马上返回,而是继续执行 finally 块中的语句,如果此处存在 return 语句,
则在此直接返回,无情丢弃掉 try 块中的返回点。

【强制】在调用RPC、二方包或动态生成类的方法时,捕获异常时必须使用Throwable类拦截

为避免调用时,无法找到方法,捕获异常时,应使用Throwable,避免NoSuchMethodError无法捕获。

【建议】防止NPE场景

编码过程中,需时刻关注空指针异常,避免因空指针异常导致业务异常。

【建议】一个方法不应抛出超过5个异常

方法抛出过多的异常,会加重调用方的异常处理工作,同时也表示该方法承担了过多的职责,不符合职责单一的原则。

日志规范

【强制】不应使用System.out或System.err打印异常,而应使用日志框架

【强制】不应直接使用日志实现框架中的API,而应使用日志门面框架的API

应面向接口编程,而不应面向实现编程。这样做,有利于统一日志处理方式——更换日志实现框架是,无需修改现有代码。

【强制】应根据日志场景选择合适的日志级别,避免只使用一种级别

开发环境可以输出trace或debug日志,生产环境不应输出trace或debug级别日志。

【强制】打印日志时,不应打印敏感信息

对于敏感信息,不应通过日志打印出来,这会导致敏感信息泄露,带来安全问题。

【建议】尽量使用英文记录日志,不建议使用其他语言

参考

Java开发手册 嵩山版 阿里巴巴

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值