docs/zh-cn/doc/开发规范/编码规范.md
2023-08-21 12:02:25 +08:00

393 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# JCNC编码规范
[1 说明](#1-说明)
* [1.1 范围](#11-范围)
* [1.2 术语和定义](#12-术语和定义)
[2 排版规则](#2-排版规则)
* [2.1 编码](#21-编码)
* [2.2 页宽](#22-页宽)
* [2.3 换行](#23-换行)
* [2.4 缩进](#24-缩进)
* [2.5 空行](#25-空行)
* [2.6 大括号](#26-大括号)
* [2.7 小括号](#27-小括号)
* [2.8 空格](#28-空格)
* [2.9 TODO](#29-todo)
* [2.10 import](#210-import)
* [2.11 变量](#211-变量)
[3 命名规范](#3-命名规范)
* [3.1 package](#31-package)
* [3.2 Class](#32-class)
* [3.3 Interface](#33-Interface)
* [3.4 方法命名](#34-方法命名)
* [3.5 变量](#35-变量)
[4 注释规范](#4-注释规范)
* [4.1 文档注释](#41-文档注释)
* [4.2 块注释](#42-块注释)
* [4.3 单行注释](#43-单行注释)
* [4.4 注意事项](#44-注意事项)
[5 编程技巧](#5-编程技巧)
* [5.1 类](#51-类)
* [5.2 方法](#52-方法)
* [5.3 控制语句](#53-控制语句)
* [5.3 数据校验](#54-数据校验)
[Creators](#creators)
## 1 说明
### 1.1 范围
本规范规定了使用Java语言时排版、注释、命名、编码的规则和建议。
本规范适用于使用Java语言成的产品和项目。
### 1.2 术语和定义
* 规则:必须遵守
* 建议:有充足的理由时可不遵守,但必须优先考虑
* 格式:对规范格式的说明或模板
* 说明:对规范或建议进行的必要解释
* 示例:对规范或建议从正反两方面给出的例子
* 补充:一些实践技巧或额外的说明
## 2 排版规则
### 2.1 编码
**规 则IDE的text file encoding设置为UTF-8。**
**规 则IDE中文件的换行符使用Unix格式不要使用windows格式。**
### 2.2 页宽
**规 则编辑器列宽应设置为100列**
**说 明:** 当一行代码的长度过长时为了阅读方便应该换行展示。但因为每个人的字体设置屏幕大小有所不同因此需要统一列宽为100列。
**补 充:**
在Eclipse中我们可以设置自动排版的单行代码最大宽度。选择【Window】→【Preferences】→【Java】→【Code Style】→【Formatter】点击“new”新建一个“Profile”若已经是自定义的profile则不需要新建。选择选项卡【Line Wrapping】,修改下边的“Maximum line width”为100。
在Eclipse中我们可以在编辑界面设置一条参考线提醒我们代码宽度。选择【Window】→【Preferences】→【General】→【Editors】→【Text Editors】。将右侧的单选框“Show print margin”设置为选中状态然后设置下边的“Print margin column”为100。
### 2.3 换行
**规 则第二行相对第一行缩进4个空格从第三行开始不再缩进而是与第二行保持同级。**
**规 则:运算符、方法调用的点符号与下文一起换行。**
**规 则:在多个参数超长时,逗号后换行。**
**示 例:**
```java
//符合规范
StringBuffer sb = new StringBuffer();
//超过100个字符的时候换行缩进4个空格并且方法钱的点符号一起换行
sb.append("wan").append("fang")...
.append("shu")...
.append("ju")...
.append("gu");
//在逗号后换行
method(arg1, arg2, arg3, ...argx,
argx1)
```
### 2.4 缩进
**规 则程序块需要采用缩进风格编写缩进为4个空格。**
**说 明:** 不同的编辑工具会导致Tab字符的宽度不统一在编码时应注意其可能造成的问题。
**补 充:**
在Eclipse中我们可以设置Tab的宽度和输入空格数。
选择【Window】→【Preferences】→【General】→【Editors】→【Text Editors】。将右侧的“Display tab width”设置为4将单选框“Insert spaces for tabs”设置为选中状态。
选择【Window】→【Preferences】→【Java】→【Code Style】→【Formatter】点击“new”新建一个“Profile”若已经是自定义的profile则不需要新建。选择选项卡【Indentation】,将左侧的下拉框“Tab policy”改为Spaces only。然后修改“Tab size”为4。
### 2.5 空行
**规则:独立的程序块与变量声明之间加空行分割**
**示 例:**
```java
//不符合规范
if(log.getLevel() < LogConfig.getRecordLevel()){
return;
}
LogWriter writer;
int index;
```
```java
//符合规范
if(log.getLevel() < LogConfig.getRecordLevel()){
return;
}
LogWriter writer;
int index;
```
### 2.6 大括号
**规 则:使用大括号(即使是可选的)**
**说 明:** 大括号与if, else, for, do, while即使只有一条语句或是空也应该把大括号写上。
**示 例:**
```java
//不符合规范的
if(writeToFile)
writeFileThread.interrupt();
```
```java
//符合规范的
if(writeToFile){
writeFileThread.interrupt();
}
```
**规 则对于非空块和块状结构大括号遵循Kernighan和Ritchie风格紧凑风格。**
**说 明:**
* 左大括号前不换行
* 左大括号后换行
* 右大括号前换行
* 如果右大括号是一个语句、函数体或类的终止,则右大括号后换行; 否则不换行。例如如果右大括号后面是else或逗号则不换行
**示 例:**
```java
//不符合规范
if(isOk)
{
someThing();
}
else
{
otherThing();
}
```
```java
//符合规范
if(isOk){
someThing();
}else{
otherThing();
}
```
**补 充:**
Kernighan和Ritchie风格指的是Kernighan和Ritchie的《C Programming Language》一书中约定的“大括号放在同一行”规则。这种编码风格比较紧凑也是Java官方和Google等诸多主流公司遵循的编码风格。
**建 议:空块可以简洁的写成{},除非它是多块语句的一部分。**
**说 明:** 一个空的块状结构里什么也不包含,大括号可以简洁地写成{},不需要换行。例外:如果它是一个多块语句的一部分(if/else 或 try/catch/finally) ,即使大括号内没内容,右大括号也要换行。
**示 例:**
```java
void doNothing() {}
```
### 2.7 小括号
**规 则:用小括号来限定计算优先级**
**说 明:** 没有理由假设代码的阅读者能够清晰的记住整个Java运算符优先级表。
###2.8 空格
**规 则:函数参数在“,”后需要加空格。**
**规 则:各种双目操作符,比如“=”,“<”等,前后都要加空格。**
**规 则if, while等关键字后面需要有空格。**
**补 充:** 基本上Eclipse的自动格式化功能就能保证这些空格的正确使用。
### 2.9 TODO
**规 则TODO用于任务标记要避免出现无用的TODO标记**
**说 明:** 自动生成代码中如果有TODO标记请根据需要编写注释或删除TODO标记避免产生无用的TODO影响他人跟踪任务。
### 2.10 import
**规 则import不要使用通配符**
**说 明:** 不要出现类似这样的import语句import java.util.*。使用通配符会造成歧义及不可预期的冲突或bug。程序应保持清晰、易懂、无歧义。
**规 则import不要引用不需要的包**
### 2.11 变量
**规 则:每次只声明一个变量**
**说 明:** 不要使用组合声明int a,b;),减少歧义性,增强可读性
**规 则:需要时才声明,并尽快进行初始化**
**规 则使用非C风格的数组声明**
**说 明:** 使用String[] args而非String args[]
**建 议:谨慎的使用公共变量**
**说 明:** 公共变量是增大模块间耦合的原因之一,应减少没必要的公共变量以降低模块间的耦合度。
## 3 命名规范
**规 则:命名应尽可能做到见名知意,力求语义表达清晰完整。**
**规 则:代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。**
**规 则:代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。**
### 3.1 package
**规 则:包名均采用小写**
**建 议:包名一般为一个单词**
**规 则内部包名规则一般为com.部门名称/站点域名.产品名/项目名.模块名通用包放在com.wanfangdata下**
**说 明:** 由于历史遗留原因,部分内部包名格式为:部门名称.产品名/项目名.模块名。原则上,新建的包不要用此命名规则,但暂时也不修改此规则的包名
### 3.2 Class
**规 则:类的命名应该都是名词**
**规 则类名第一个字母要为大写其他每个单词的第一个字母为大写UpperCamelCase**
**规 则:类名要用完整的单词,除非是被公认的单词缩写**
**规 则抽象类命名应以Abstract为开头**
**规 则异常类命名使用Exception结尾**
**规 则测试类命名以它要测试的类名称开始以Test结尾**
**建 议:如果使用了设计模式,建议在类(接口)命名中体现出具体的设计模式**
**建 议枚举类名以Enum后缀结束美剧成员名称需要全部大写单词间用下划线分隔。**
**示 例:**
```java
public class BalanceLimitAccountHandler;
public interface SqlSessionFactory;
public class LoginProxy;
```
### 3.3 Interface
**规 则:接口名的命名应该是名词或形容词**
**规 则接口名应以大写的I开头其他单词第一个字母都要大写UpperCamelCase**
**规 则:接口名要用完整的单词,除非是被公认的单词缩写**
**建 议接口类中的方法和属性不要加任何修饰符好public也不要加。**
### 3.4 方法命名
**规 则:方法名应以动词或惯用短语描述**
**规 则方法名第一个字母都要小写其他每个单词第一个字母都要大写lowerCamelCase**
**建 议:方法名中不要加入对象名字,可能会带来误解。**
**说 明:** 因为对象本身已经包含在调用语句中了
### 3.5 变量
**规 则:应避免用单个字符命名变量**
**规 则:代码中严禁使用拼音与英文混合的方式,优先使用英文而非拼音**
**规 则参数名第一个字母使用小写其他每个单词第一个字母大写lowerCamelCase**
**规 则:常量名应该为名词或名词短语**
**规 则常量名每一个字母都应为大写单词之间用“_”分开。**
**规 则:不允许出现任何魔法值(未经定义的常量)直接出现在代码中。**
**建 议:不要使用一个常量类维护所有常量,应该按常量功能进行归类,分开维护。**
**规 则long或者Long初始赋值时必须使用大写的L不能是小写的l小写容易跟数字1混淆造成误解。**
**规 则局部变量名第一个字母使用小写其他每个单词第一个字母大写lowerCamelCase。**
**规 则:局部变量名可以更宽松的使用缩写,但除了临时变量和循环变量应避免单字符命名。**
**规 则POJO类中布尔类型的变量都不要加is否则部分框架解析会引起序列化错误。参考阿里java规范**
**说 明:**
定义为基本数据类型Boolean isSuccess的属性它的方法也是isSuccess()RPC框架在反向解析的时候“以为”对应的属性名称是success导致属性获取不到进而抛出异常。
## 4 注释规范
### 4.1 文档注释
**规 则一般情况下源程序有效注释量必须在30%以上。**
**规 则接口、Action方法、工具类的public方法等凡是提供给外界调用的方法都必须添加文档注释。**
**规 则文档注释用于描述Java的类、接口、构造函数、方法一级成员变量field。**
**规 则:类和接口的注释在 package 关键字之后class 或者 interface 关键字之前。**
**规 则:类和接口的注释内容:类的注释主要是一句话功能简述、功能详细描述。**
**说 明:** 可根据需要列出:版本号、生成日期、作者、内容、功能、与其它类的关系等。 如果一个类存在Bug请如实说明这些Bug
**规则:对于接口需要标注**
```java
/**
* 〈一句话功能简述〉
* 〈功能详细描述〉
* @author [作者]
* @see [相关类/方法]
* @deprecated
*/
```
**示例:**
```java
/**
* LogManager 类集中控制对日志读写的操作。
* 全部为静态变量和静态方法,对外提供统一接口。分配对应日志类型的读写器,
* 读取或写入符合条件的日志纪录。
* @author 张三,李四,王五
* @see LogIteraotor
* @see BasicLog
*/
```
**规 则:类属性、公有和保护方法注释:写在类属性、公有和保护方法上面**
**规 则:成员变量使用文档注释,而不是单行注释或尾部注释**
**规 则:成员变量注释内容:成员变量的意义、目的、功能,可能被用到的地方**
**规 则:公有和保护方法注释内容:列出方法的一句话功能简述、功能详细描述、输入参数、输出参数、返回值、违例等**
**说明:**
```java
/**
* 〈一句话功能简述〉
* 〈功能详细描述〉
* @param [参数1] [参数1说明]
* @param [参数2] [参数2说明]
* @return [返回值类型] [返回类型说明]
* @exception/throws [违例类型] [违例说明]
* @see [类、类#方法、类#成员]
* @deprecated
*/
```
**示 例:**
```java
/**
* 根据日志类型和时间读取日志。
* 分配对应日志类型的LogReader 指定类型、查询时间段、条件和反复器缓冲数,
* 读取日志记录。查询条件为null或0表示无限制反复器缓冲数为0读不到日志。
* 查询时间为左包含原则,即 [startTime, endTime) 。
* @param logTypeName 日志类型名(在配置文件中定义的)
* @param startTime 查询日志的开始时间
* @param endTime 查询日志的结束时间
* @param logLevel 查询日志的级别
* @param userName 查询该用户的日志
* @param bufferNum 日志反复器缓冲记录数
* @return LogIterator 结果集,日志反复器
* @since CommonLog1.0
*/
public static LogIterator read(String logType, Date startTime, Date endTime,
int logLevel, String userName, int bufferNum)
```
### 4.2 块注释
**规 则:块注释用来为文件、方法、数据结构和算法进行描述或是用来划分文件的模块**
**规 则:块注释一般放在每个文件的开始或是每个模块、方法的前面,也可能放在方法之内**
**规 则:在块注释前应该有一个空行,以便同其他代码进行分割**
### 4.3 单行注释
**规 则:简短的注释可以只用一行来说明,并与后面的代码进行相同的缩进**
**规 则:单行注释如果一行写不下,就应该考虑使用块注释**
**规 则:在单行注释前应该有一个空行,以便痛其他代码进行分割**
### 4.4 注意事项
**规 则:注释必须与代码同步更新**
**建 议:应避免注释中提供代码中已清晰表达出来的重复信息**
**建 议:当要写非文档注释的时候,应考虑下是否可以将代码写的更清晰易懂**
**说 明:** 过多的非文档注释,往往反映出代码的低质量
**建 议TODO与FIXME注释格式建议包含标记人标记时间[预计处理时间]**
## 5 编程技巧
### 5.1 类
**规 则:明确类的功能,精确(而非近似)地实现类的设计,一个类仅实现一组相近的功能**
**说 明:** 划分类的时候,应该尽量把逻辑处理、数据和显示分离,实现类功能的单一性
**示 例:** 数据类不能包含数据处理的逻辑,通信类不能包含显示处理的逻辑
**规 则所有的数据类必须重载toString() 方法,返回该类有意义的内容**
**说 明:** 如果父类中已经实现了较为合理的toString()方法,子类可以继承而不必重写
**规 则只要重写equals就必须重写hashCode。**
**规 则因为Set存储的是不重复的对象依据hashCode和equals进行判断所以Set存储的对象必须重写这两个方法。**
**规 则如果自定义对象做为Map的键那么必须重写hashCode和equals。**
**建 议:@Override能用则用**
**说 明:** 只要是合法的,就把@Override注解用上
**补 充:** 参考自谷歌编码规范
### 5.2 方法
**规 则:参数个数>4个时抽取参数类**
**建 议参数列表中请尽量不取用true、false类参数避免因为调用者不明确导致的问题**
**建 议返回调用函数方应该知道的消息慎用void**
**建 议返回空的集合时使用Collections.empty方法不要直接返回null**
**规 则每个方法不得超过100行**
**建 议超过50行的代码建议考虑重构**
**规 则:方法不得包含隐式功能**
**说 明:**getIdsFromList(List modelList)仅应该执行从list获取id的操作而不应该对list有修改
**规 则:避免使用不易理解的数字,用有意义的标识来替代**
**规 则:涉及物理状态或者含有物理意义的常量,不应直接使用数字,必须用有意义的静态变量来代替**
### 5.3 控制语句
**规 则在一个switch块内都必须包含一个default语句并且放在最后即使它什么代码也没有**
**规 则在if/else/for/while/do语句中必须使用大括号即使只有一行代码避免使用下面的形式if (condition) statements;**
**规 则尽量少用else**
**示 例:**
```java
//不符合规范
if(condition)
{
...
return obj;
}
//接着写else的业务逻辑代码
```
### 5.4 数据校验
**建 议:方法中需要进行参数校验的场景**
* 调用频次低的方法
* 执行时间开销很大的方法,参数校验时间几乎可以忽略不计,但如果因为参数错误导致中间执行回退,或者错误,那得不偿失。
* 需要极高稳定性和可用性的方法
* 对外提供的开放接口不管是RPC/API/HTTP接口
* 敏感权限入口
**建 议:方法中不需要参数校验的场景**
* 极有可能被循环调用的方法,不建议对参数进行校验。但在方法说明里必须注明外部参数检查。
* 底层的方法调用频度都比较高,一般不校验。(参数错误不太可能到底层才会暴露问题)
* 被声明成private只会被自己代码所调用的方法。
## Creators
引用自[编码规范](https://github.com/wanfangdata/guide/blob/master/java%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83/%E7%BC%96%E7%A0%81%E8%A7%84%E8%8C%83.md)
原作者:[梅葆瑞](https://github.com/meibaorui) [李辉]() [张锐](https://github.com/pizirui)