栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java 代码规范

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java 代码规范

新增:项目结构规范、字典编码规范

修改:代码注释

版本:v1.1.1 20200508

修改:数据库必备字段修改:字典编码规范

版本:v1.1.2 20211119

修改:请求参数修改:字典编码规范

文档规定东方大唐研发中心Java开发规范,包括命名规范、代码注释、代码格式、控制语句、异常处理、SQL语法、文件组织、版本发布、安全规范、其他规范。本文档参考《阿里巴马Java开发手册》,并根据实际情况进行了裁剪,本文档会在工作实际中进行修订。

一、命名规范

1.1 代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。
以下是错误示例:

_name / __name / $Object / name_ / name$ / Object$

1.2 代码中的命名严禁使用拼音与英文混合的方式,严禁使用各种无意义的缩写,或无意义的名称。更不允许直接使用中文的方式。
说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使纯拼音命名方式 也要避免采用。国际通用的名称,可视同英文。

alibaba / taobao / youku / hangzhou

以下是错误示例:

DaZhePromotion  // [打折] 
getPingfenByName()  // [评分] 
int 循环次数 = 3

1.3 类名使用 UpperCamelCase 风格,必须遵从驼峰形式,但以下情形例外:(领域模型 的相关命名)DO / BO / DTO / VO 等(后缀)。

MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion

以下是错误示例:

macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion

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

localValue / getHttpMessage() / inputUserId

1.5 常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。

MAX_STOCK_COUNT

以下是不推荐示例:

MAX_COUNT

1.6 抽象类命名使用 Abstract 或 base 开头;异常类命名使用 Exception 结尾;测试类 命名以它要测试的类的名称开始,以 Test 结尾。

1.7 中括号是数组类型的一部分,数组定义如下:String[] args; 反例:请勿使用 String args[]的方式来定义。

1.8 包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用 单数形式,但是类名如果有复数含义,类名可以使用复数形式。

com.geostar.geoios.util     // 应用工具类包名
MessageUtils    // 此规则参考 spring 的框架结构

1.9 杜绝完全不规范的缩写,避免望文不知义。

AbstractClass “缩写”命名成 AbsClass
condition “缩写”命名成 condi,此类随意缩写严重降低了代码的可阅读性。

1.10 接口和实现类的命名有两套规则:TODO 整理
对于 Service 和 DAO类,基于SOA的理念,暴露出来的服务一定是接口,内部的实现类用 Impl 的后缀与接口区别。

public class CacheServiceImpl implements CacheService{
}

如果是形容能力的接口名称,取对应的形容词做接口名(通常是–able 的形式)。

public class AbstractTranslator implements Translatable{
}

1.11 枚举类名要带上Enum后缀,枚举成员名称需要全大写,单词间用下划线隔开。

public enum DealStatusEnum {  
    SUCCESS, UNKOWN_REASON 
}  

1.12 数据结构命名后面要加后缀,以标识数据结构类型,数组类型的命名必须为复数。自定义类型的变量可以采用本身的名称,把首字母改为小写。

String[] persons;               // 数组类型
List personList;        // List数据类型
Map fieldMap;    // Map数据类型
Set registeredSet;       // Set数据类型
UserInfo userInfo;              // 自定义数据类型

1.13 布尔类型变量命名规则。
临时变量:使用is、has、can作为前缀表示临时逻辑变量,或使用动词的过去式表结果状态。不得使用flag、status、state等表示含义模糊逻辑变量,变量的命名应能地表达逻辑判断的内容。

boolean hasChildNode,hasMoney;  //表示是否有XXX
boolean canWrite,canEat,canFly; //表示是否具备某些条件
boolean isLoading,isHight,isBoy;// 表示是否处于某种状态
boolean removed,found,done,uploaded;// 使用动词的过去式表示某项操作是否完成

成员变量:对于POJO类中的布尔类型成员变量,都不要加is,直接使用去掉is前缀后变量名,否则可能引起序列化错误。

public class Bookstore{
    private boolean closed;
    private boolean getClosed{
        return this.closed;
    }
    private boolean setClosed(boolean isClosed){
        this.closed = isClosed;
    }
}

说明:根据JavaBean的规范,布尔类型(boolean)变量通过IDE自动生成的getter方法为isProperty(),而不是getProperty()。如果成员变量名为isClosed,则通过IDE生成的getter方法是isClosed(),这样会导致序列化框架识判变量名为closed,导致无法正确的赋值。
注意:对于包装的布尔类型(Boolean)变量,通过IDE自动生成的getter方法还是getProperty()。如果成员变量为:Boolean isClosed,则生成的getter方法是getIsClosed(),则不会出现序列化的问题。
1.14 不允许出现任何魔法值(即无意义的常量) 直接出现在代码中,
错误示范

String key = "ID#taobo_"+ tradeID;
    cache.put(key,value);
二、代码注释

2.1 类、类属性、类方法的注释必须使用Javadoc规范,使用格式,不得使用 //xxx 方式。
说明:在 IDE 编辑窗口中,Javadoc 方式会提示相关注释,生成 Javadoc 可以正确输出相应注 释;在 IDE 中,工程调用方法时,不进入方法即可悬浮提示方法、参数、返回值的意义,提高 阅读效率。

public int add(int p1, int p2) {
}

2.2 所有的抽象方法(包括接口中的方法)必须要用Javadoc注释、除了返回值、参数、 异常说明外,还必须指出该方法做什么事情,实现什么功能。
说明:对子类的实现要求,或者调用注意事项,请一并说明。
2.3 所有的类都必须添加功能、创建者、创建时间、版本信息。

public class Math {
}

2.4 方法内部单行注释,使用//注释。方法内部多行注释 使用注释,注意与代码对齐。

public int getPersonSex(int personId) {
    // 获取人员信息
    Person person = dao.getPerson(personId);
    
    
    if (null == person){
        return -1;
    }
    int sex = person.getSex();
    
    return sex;
}

2.5 所有的枚举类型字段必须要有注释,说明每个数据项的用途。

2.6 所有control层做好,swagger 的注解,必须指明这个接口的作用,入参说明,对于有需要特别注意的点使用note注解说明

2.7 代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻辑 等的修改。
说明:代码与注释更新不同步,就像路网与导航软件更新不同步一样,如果导航软件严重滞后, 就失去了导航的意义。

三、代码格式(推荐)

3.1 大括号的使用约定。如果是大括号内为空,则简洁地写成{}即可,不需要换行;如果 是非空代码块则:

左大括号前不换行。左大括号后换行。右大括号前换行。右大括号后还有 else 等代码则不换行;表示终止右大括号后必须换行。

3.2 缩进采用 4 个空格,禁止使用 tab 字符。
说明:如果使用 tab 缩进,必须设置 1 个 tab 为 4 个空格。可在 eclipse 中勾选 insert spaces for tabs。

public static void main(String[] args) {
    // 缩进 4 个空格
    String say = "hello";

    //	大括号格式风格
    if (flag == 1) { 
        System.out.println("world");
        // 右大括号前换行,右大括号后有 else,不用换行
    } else { 
        System.out.println("ok");
        // 在右大括号后直接结束,则必须换行
    }
}

3.3 单行字符数限制不超过 120 个,超出需要换行,换行时遵循如下原则:

第二行相对第一行缩进 4个空格,从第三行开始,不再继续缩进,参考示例。运算符与下文一起换行。方法调用的点符号与下文一起换行。在多个参数超长,逗号后进行换行。在括号前不要换行。

StringBuffer sb = new StringBuffer();
//超过 120 个字符的情况下,换行缩进 4个空格,并且方法前的点符号一起换行
sb.append("zi").append("xin")...
    .append("huang")...
    .append("huang")...
    .append("huang");
method(args1, args2, args3, ...,
    argsX);

以下是错误示例:

StringBuffer sb = new StringBuffer();
//超过 120 个字符的情况下,不要在括号前换行
sb.append("zi").append("xin")...append
    ("huang");

//参数很多的方法调用可能超过 120 个字符,不要在逗号前换行
method(args1, args2, args3, ...
    , argsX);

3.4 IDE 的 text file encoding 设置为 UTF-8; IDE 中文件的换行符使用 Unix 格式, 不要使用 windows 格式。

四、控制语句

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

4.2 在 if/else/for/while/do 语句中必须使用大括号,即使只有一行代码,避免使用下面的形式:
错误示例

if (condition) statements;

4.3 尽量少用 else, if-else 的方式可以改写成:
通过return 返回,结束执行逻辑

if(condition){
    ...
    return obj;
}

// 接着写 else 的业务逻辑代码;

说明:如果非得使用 if()…else if()…else…方式表达逻辑,【强制】请勿超过 3 层

4.4 不要在条件判断中执行其它复杂的语句,将复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性。

//伪代码如下
boolean existed = (file.open(fileName, "w") != null) 
    && (...) || (...); 
if (existed) {
    ...
}

以下是错误示例:

if ((file.open(fileName, "w") != null) && (...) || (...)) {
    ...
}
五、异常处理

5.1 不要捕获 Java 类库中定义的继承自 RuntimeException 的运行时异常类,如:IndexOutOfBoundsException /NullPointerException,这类异常由程序员预检查来规避,保证程序健壮性。

if(obj != null) {
    ...
}

以下是错误示例:

try { 
    obj.method();
} catch(NullPointerException e){
    ...
}

5.2 异常不要用来做流程控制,条件控制,因为异常的处理效率比条件分支低。

5.3 对大段代码进行 try-catch,这是不负责任的表现。catch时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的 catch 尽可能进行区分 异常类型,再做对应的异常处理。

5.4 有 try 块放到了事务代码中,catch异常后,如果需要回滚事务,一定要注意手动回滚事务。

5.5 finally 块必须对资源对象、流对象进行关闭,有异常也要做 try-catch。

5.6 不能在 finally 块中使用 return,finally 块中的 return返回后方法结束执行,不会再执行 try 块中的 return 语句。

5.7 注意防止 NPE(空指针异常) 产生的场景:

返回类型为包装数据类型,有可能是 null,返回 int 值时注意判空。 反例:public int f(){ return Integer 对象}; 如果为 null,自动解箱抛 NPE。数据库的查询结果可能为 null。集合里的元素即使 isNotEmpty,取出的数据元素也可能为 null。远程调用返回对象,一律要求进行 NPE 判断。对于 Session 中获取的数据,建议 NPE 检查,避免空指针。级联调用 obj.getA().getB().getC();一连串调用,易产生 NPE。

5.8 对于系统中的异常,捕获必须进行处理,如果不处理,只是简单的打印日志,直接交给spring框架的全局异常捕获机制即可。

六、数据库规约

6.1 建表原则,表名字段名统一小写,使用下划线分割
6.2 建表类型选择(推荐)

整数,当明确知道大小低于127的时候,选用tinyint,其他情形选用int小数,没有特殊情况不要使用小数,使用字符串代替字符串 使用varchar,禁止统一varchar(255),应当按需取最小值,eg:varchar(32) ,字符多时使用text图片等非文字类容,使用blob,日期,使用datatime 存储yyyy-MM-dd HH:mm:ss, 后端接参有统一格式处理,不用再单独处理,前端根据需要进行相关格式化

6.3 不要使用 count(列名)或 count(常量)来替代count(*),count(*)就是 SQL92定义的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。
说明:count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行。

select count(*) from student;

6.4 count(distinct col)计算该列除NULL之外的不重复数量。
注意:count(distinct col1, col2) 如果其中一列全为 NULL,那么即使另一列有不同的值,也返回为 0。

6.5 当某一列的值全是 NULL 时,count(col)的返回结果为 0,但 sum(col)的返回结果为NULL,因此使用 sum()时需注意 NPE 问题。

6.6 在代码中写分页查询逻辑时,若count为0应直接返回,避免执行后面的分页语句。

6.7 不得使用外键与级联,一切外键概念必须在应用层解决。
概念解释:学生表中的 student_id 是主键,那么成绩表中的 student_id 则为外键。 如果更新学生表中的 student_id,同时触发成绩表中的 student_id 更新,则为级联更新。 外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数 据库更新风暴的风险;外键影响数据库的插入速度。

6.8 禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。
6.9 禁止使用数据库函数,理由同上

6.10 数据库表结构修改,强制写SQL脚本修改,不得直接使用工具手动修改。
6.11 数据

八、API接口规范

8.1 API命名规范
完整的API格式如下:

[http|https]://[ip]:[port]/[module]/[action]

[http|https] http协议或https协议。[ip]和[port] IP地址和端口,如:192.168.100.104:8080、www.geostaryun.com:8088等[module] 模块或业务名称,可以包括子模块,子模块为可选,如:book/category、book/sale等。[action] 执行的动作,如:add、update、delete、list、get等。
说明:命名必须统一使用驼峰命名法。如upperCamelCase、queryCandidate、queryProcessInstance等。

接口中的action命名规范:

新增接口,如新增一个地址、新增一名用户
使用add名称或以add为前缀,如:http://192.168.0.1:8088/user/add

修改接口,如修改用户信息
使用update名称或以update为前缀,如:http://192.168.0.1:8088/user/update

删除接口,如删除用户信息
使用delete名称或以delete为前缀,如:http://192.168.0.1:8088/user/delete

获取接口,如获取用户信息
使用get名称或以get为前缀,如:http://192.168.0.1:8088/user/get、http://192.168.0.1:8088/api/v1/user/getAlias

获取列表接口,如获取一组用户信息
使用list名称或以list为前缀,如:http://192.168.0.1:8088/user/list、http://192.168.0.1:8088/api/v1/user/listUser
如果需要不分页获取所有数据,加上all标识,如:http://192.168.0.1:8088/user/listAll

关联数据接口,如给用户关联角色、给角色关联权限
使用bind名称或以bind为前缀,如:http://192.168.0.1:8088/user/bindRole、http://192.168.0.1:8088/api/v1/role/bindPermission

移动关联关系接口,如移除用户的管理员角色
使用remove名称或以remove为前缀,如:http://192.168.0.1:8088/user/removeRole、http://192.168.0.1:8088/api/v1/role/removePermission

其他接口
文件上传,使用upload名称或以upload为前缀。如:http://192.168.0.1:8088/doc/upload、http://192.168.0.1:8088/api/v1/doc/uploadImage
批量操作,使用batch名称或以batch为前缀。如批量上传、批量增加。http://192.168.0.1:8088/api/v1/doc/batchUpload、http://192.168.0.1:8088/user/batchAdd
接口功能,不在上述范围内的请谨慎命名,与上级协商补充。
8.2 请求参数规范

请求方式
简单普通数据获取与查询:GET
数据修改、删除:POST
身份验证与敏感数据:POST
参数超过3个的查询:POST
禁止使用put, delete 等请求方式,因为部分框架可能不支持,比如feign框架

请求入参
根据实际需要,参数最小化原则。不需要的参数一律不暴露出来,比如新增的时候不需要ID,就不要暴露这个字段给前端。可以定义多个VO对象
参数的定义最好由前端定义。依赖倒置原则,前端更接近业务,有前端制定标准。

请求出参
统一使用com.wiilead.it.common.vo.ResponseVO 结构, 相关返回字段推荐由前端定义。
示例:

    public ResponseVO saveAssetsType(@RequestBody AssetsAllocationVO assetsAllocationVO) {
        try {
            JSonObject jsonObject = assetsAllocationService.saveAssetsAllocation(assetsAllocationVO);
            if (jsonObject!=null&& !(boolean)(jsonObject.get("flag"))){
                return ResponseVO.success("不能操作审批中或已调拨的订单", null);
            }
            return ResponseVO.success("资产调拨新建成功", null);
        } catch (Exception e) {
//            e.printStackTrace();
        	logger.error("{}",e);
            return ResponseVO.fail("资产调拨新建失败", null);
        }
    }

(7)列表请求特殊规范
pageNo :页数,从1开始。例如:{ “pageNo”: 1 }
pageSize : 每页数量。

九、项目结构

独立微服务 十、JAVA技术选择规范

(1)ORM框架采用,mybatis-plus 拒绝使用任何其他第三方ORM框架,说明:mybatis-plus 是mybatis 的封装,针对单表操作使用简单,保留了所有的mybatis 的功能
尽量使用单表查询,将多表查询拆分。 为了数据库兼容,批量查询,避免循环查询。

(2)API接口,使用统一的ResponseVO对象接收,参考com.wiilead.it.common.vo.ResponseVO.java 该对象有成功和失败的方法封装
使用示例:

     try {
        	Boolean modelExist = modelService.modelExist(bpmnModelVO);
        	if(modelExist) {
        		return ResponseVO.fail("模板标识不能重复",null);
        	}
            modelService.modelSave(bpmnModelVO);
            return ResponseVO.success("模板信息存储成功",null);
        }catch (Exception e){
            return ResponseVO.fail("模板信息存储失败",null);
        }

(3) 内部Feign 调用,建议直接返回象需要对,避免直接返回Response

推荐使用

@FeignClient(value = ServiceNameConstants.WIILEAD_ALM_SERVICE, fallbackFactory = RemoteBugServiceFallbackFactory.class)
public interface RemoteBugService {

	@GetMapping("/bug/fegin/findAllBugVO")
	 List findAllBugVO(@RequestBody BugVO vo, @RequestHeader(SecurityConstants.FROM) String from);
	
} 

避免使用

@FeignClient(value = ServiceNameConstants.WIILEAD_PM_SERVICE, fallbackFactory = RemoteProjectInfoServiceFallbackFactory.class)
public interface RemoteProjectInfoService {
    @GetMapping("/projectInfo/findAllFeign/{strategy}")
    ResponseVO findAll(@PathVariable("strategy") String strategy, @RequestHeader(SecurityConstants.FROM) String from);
}

(4)VO 对象是纯净的VO,它只有属性字段。避免依赖于任何第三方jar,推荐Service层返回model 中的对象,controller层返回VO中的对象

(5)所有的表数据带上is_delete 字段,类型char,长度1. 值:0:代表未删除,1代表删除。不要使用魔法值,使用DeleteFlageEnum枚举!所有删除走逻辑删除。office_id, create_by, create_date, update_by, update_date.

(6)删除,不推荐使用级联删除。可以给出提示,有关联关系,让用户自己处理关联数据

(7)父子自关联关系表,根节点避免空值,推荐使用:0 作为根节点的ParentId

十一、 缓存规范

(1) 项目中所有的缓存使用redis 缓存,使用Redistemplate 操作Redis 数据,避免任何其他方式的缓存

(2) 选取合适的Redis 数据结构,避免大量的Redis 数据操作

(3) 查询数据,对于走了Redis 没有找到的,记得要去数据库中查找,不能只走缓存

第三方库

所有的jar依赖都使用wiilead-cloud 父pom文件中的依赖,尤其是依赖版本

附1:常见名称命名规范

关于缩写名词的说明:
a. 尽可能多用全称,少用缩写;
b. 单个词汇出现的时候,不允许缩写,已固定的缩写(如Id,I是大写)除外;
c. 两个或以上单词都可以缩写的时候,只允许一个单词使用缩写,建议第一个单词使用缩写。

工作流

序号术语命名缩写
1流程process
2流程实例processInstanceprocInst
3活动(任务)定义activity
4活动任务实例activityInstanceactInst,taskInst,task
5待办todo/TODO
6已办done/DONE

系统名称

序号术语命名缩写
1工作台workbench
2文档document
3系统system
4视图view
5流程workflow
6菜单menu
7角色role
8消息message
9通知notice
10编码code
11部门department

项目管理

序号术语命名缩写
1战略strategy
3项目组合projectGroup
4预算budget
5合同contract
6采购purchase
7需求requirement
8资源resource
9产品product
10版本version
11迭代sprint
12故事story
13看板board
14团队team
15计划schedule
16任务task
17里程碑milestone
18问题problem
19风险risk
20变更change
21报告report
22项目project

测试

序号术语命名缩写
1测试test
2测试用例testCase
3缺陷bug

操作

序号术语命名缩写
1新增add
2修改update
3删除delete
4查询query
5审批approve
6通过pass
7驳回reject
8撤销revoke
9上传upload
10下载download
11复制copy
12拆分split
13完成complete
14关闭close
15变更change
16评价appraise
17申请apply
18保存save

TODO:补充所有基本命名

附2:字典编码规范
    后端所有使用字典的地方使用枚举。每一个数据字典对应一个枚举文件 在bpmn 模块的test目录下存在代码生成工具com.wiilead.it.bpmn.DictUtils
    制定对应的字典code,即可自动生成对应的枚举文件步骤一,有代码生产工具,可以自动生成,定义字典的时候定义良好的Code 有助于生成可读性良好的代码

备注:之前的字典码,经历过修改,和规范相对于的字典码已经修改,对应表在SVN上查看
SVN地址:https://120.24.183.170/svn/Wiilead/设计文档/wiilead 产品/数据字典整理.xlsx
注意:字典和枚举的使用场景
字典编码使用XXX三位编码,避免使用1,2,3
1XX-9XX 共9大类

流程审批类 6XX

序号状态编码描述
1流程审批(所有的审批类)6XX
2草稿600
3审批中610
4审批完成620
5驳回630
6废弃640

级别类,数字越小越差,越不重要

序号状态编码描述
1优先级3XX(所有的级别类)
2300
3310
4320
5较高330
6非常高340

结果状态类

序号状态编码描述
1通过不通过2XX
2通过200
3不通过210

处理过程类

序号状态编码描述
1处理过程5XX
2待处理500
3处理中510
4处理完成520
5关闭530
附2:代码生成(Eclipse)

在bpmn模块下面,有一个EntityUtils 工具类,用来生成代码。
包括controller VO 等多个文件。

在bpmn模块下面,有一个DictUtils 工具类,可以用来生成字典枚举

附3:代码规范检查插件(Eclipse)

(1)开发环境

Eclipse Juno+maven3.+JDK 1.7+

(2)安装插件

Help >> Install New Software,在地址栏中输入地址:https://p3c.alibaba.com/plugin/eclipse/update
按安装提示完成安装。

(3)使用插件

在工程目录中,右键点击目录或Java文件,在弹出的菜单中选择Alibaba Coding Guidelines Analyse,或者按快捷键Ctrl+Alt+Shift+J在代码编辑器窗口,可以查看到所有不规范代码的提示。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/760790.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号