Java开发规范

本文详细介绍了Java开发的命名、常量、代码格式、API文档、OOP、集合处理、DAO、建表和数据映射等方面的规范,包括命名风格、常量定义、代码格式化、接口与实现、枚举使用、代码复用、方法命名、API注释、覆写方法、异常处理等,旨在提升代码质量和可读性。
摘要由CSDN通过智能技术生成

(一)命名规范

  1. 【强制】类名使用 UpperCamelCase 风格,但以下情形例外:DAO / DTO / POJO 等。

    正例:MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion

    反例:macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion

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

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

    正例:MAX_STOCK_COUNT

    反例:MAX_COUNT / MaxCount / maxCount

  4. 【强制】抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类命名以它要测试的类的名称开始,以 Tests 结尾。单元测试方法以测试场景+Test 结尾。

    正例:AdminLoginTests / adminLoginSuccessTest() / adminLoginFailedTest()

    反例:AdminLoginTest / testAdminLoginSuccess()

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

    正例:org.springframework.util.CollectionUtils

  6. 【强制】杜绝完全不规范的缩写,避免望文不知义。

  7. 【强制】对于 Service ,暴露出来的服务一定是接口,内部的实现类用 Impl 的后缀与接口区别。

    正例:CacheServiceImpl 实现 CacheService 接口。

  8. 【推荐】为了达到代码自解释的目标,任何自定义编程元素在命名时,使用尽量完整的单词组合来表达其意。

    正例:在 JDK 中,表达原子更新的类名为:AtomicReferenceFieldUpdater。

    反例:变量 int temp 的随意命名方式。

  9. 【推荐】枚举类名建议带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。

    正例:枚举名字为 ProcessStatusEnum 的成员名称:SUCCESS / UNKNOWN_REASON。

  10. 【推荐】各层命名规约:

    10.1 Service/DAO 层方法命名规约

    1)获取单个对象的方法用 get 做前缀。

    2)获取多个对象的方法用 list 做前缀,复数形式结尾如:listObjects。

    3)获取分页对象的方法用 page 做前缀,复数形式结尾如:pageObjects。

    4) 获取统计值的方法用 count 做前缀。

    5) 插入的方法用 save/insert 做前缀。

    6) 删除的方法用 remove/delete 做前缀。

    7) 修改的方法用 update 做前缀。

    10.2 领域模型命名规约

    1)数据传输对象:xxxDTO,xxx 为业务领域相关的名称。

(二)常量规范

  1. 【强制】不允许任何 Magic Number(即未经预先定义的常量)直接出现在代码中。

  2. 【强制】在 long 或者 Long 赋值时,数值后使用大写的 L。

    正例:Long a = 2L

    反例:Long a = 2l / Long a = 21

  3. 【推荐】不要使用一个常量类维护所有常量,要按常量功能进行归类,分开维护。

  4. 【推荐】常量复用层次:

    4.1 包内共享常量:即在当前包下单独的 constant 目录下。

    4.2 类内共享常量:直接在类内部 private static final 定义。

  5. 【强制】同一类型不同意义的常量必须加上前缀,例如 ORDER_STATUS_XXX , XXX_TYPE_XXX。

    正例:CARD_TYPE_CASH = 1; CARD_TYPE_MEMBER_CARD = 2; CARD_TYPE_DISCOUNT = 3;

    反例:CASH = 1; MEMBER_CARD = 2; DISCOUNT = 3;

(三)代码格式

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

    1) 第二行相对第一行缩进 4 个空格,从第三行开始,不再继续缩进,参考示例。

    2) 运算符与下文一起换行。

    3) 方法调用的点符号与下文一起换行。

    4) 方法调用中的多个参数需要换行时,在逗号后进行。

    5) 在括号前不要换行,见反例。

正例:

StringBuffer sb = new StringBuffer(); 
sb.append("zi").append("xin")...
// 超过 120 个字符的情况下,换行缩进 4 个空格,点号和方法名称一起换行
.append("huang")... 
.append("huang")... 
.append("huang");

反例:

StringBuffer sb = new StringBuffer(); 
// 超过 120 个字符的情况下,不要在括号前换行
sb.append("zi").append("xin")...append 
("huang"); 
// 参数很多的方法调用可能超过 120 个字符,不要在逗号前换行
method(args1, args2, args3, ... 
, argsX); 
  1. 【强制】类的属性定义要留空行,不然加上一堆注解,分不清哪一段是哪一段。

正例:

    @ApiModelProperty(value = "账号", required = true, example = "admin")
    @NotBlank(message = "账号不能为空")
    private String account;

    @ApiModelProperty(value = "密码", required = true, example = "123456")
    @NotBlank(message = "密码不能为空")
    private String password;

反例:

    @ApiModelProperty(value = "账号", required = true, example = "admin")
    @NotBlank(message = "账号不能为空")
    private String account;
    @ApiModelProperty(value = "密码", required = true, example = "123456")
    @NotBlank(message = "密码不能为空")
    private String password;    
    @ApiModelProperty(value = "确认密码", required = true, example = "123456")
    @NotBlank(message = "确认密码不能为空")
    private String confirmPassword;
  1. 【强制】在if / else / for / while / do语句中必须使用大括号,即便是只有一行代码,也需要添加大括号。

反例:

if (condition) 
    statements;

正例:

if (condition) {
    statements;
}
  1. 【强制】禁用 import *,使包的引入更清晰明了,避免 IDE format 时相互修改 imports。

  2. 【强制】SQL 文件名称使用下划线分割,内容缩进使用4个空格。

  3. 【推荐】定义好 Reformat code 的快捷键,养成经常 format 代码的习惯。

  4. 【推荐】单个方法的总行数不超过 80 行。说明:包括方法签名、结束右大括号、方法内代码、注释、空行、回车及任何不可见字符的总行数不超过 80 行。

    说明:代码逻辑分清红花和绿叶,个性和共性,绿叶逻辑单独出来成为额外方法,使主干代码更加清晰;共性逻辑抽取成为共性方法,便于复用和维护。

  5. 【推荐】单行代码行宽应尽量避免超出 100 个字符(IDE 中的标准线),禁止出现一行必须滚动才能看清全部的代码。

  6. 【推荐】不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开来以提升可读性。

    说明:任何情形,没有必要插入多个空行进行隔开。

(四)Api 文档规约

  1. 【强制】每个 Api 参数字段都需要注明对应的中文注释,如果是 code 类型,则需要写上备注,注明每个 code 对应的注释。

  2. 【强制】禁止直接返回 POJO 作为 Api 返回参数。因为 JOOQ 生成的 POJO 无法添加 Swagger 注解,而且不是所有字段都对前端有用,造成无谓的序列化,浪费内存。

  3. 【强制】请求参数和返回参数都需要写上 exampleposition

(五)OOP 规约

  1. 【强制】外部正在调用或者第三方服务依赖的接口,不允许 api 路径,避免对接口调用方产生影响。接口过时或不再使用时,必须加@Deprecated 注解,并清晰地说明采用的新接口或者新服务是什么。

  2. 【强制】所有的覆写方法,必须加@Override 注解。

  3. 【强制】不能使用过时的类或方法。

    说明:作为调用方,有义务去考证过时方法的新实现是什么。

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

    说明:应使用 java.util.Objects.equals()

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

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

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

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

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

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

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

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

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

  7. 【强制】POJO 类必须写 toString 方法。可使用 Lombok @ToString 注解。

  8. 【强制】当列表类型返回值为空时,避免返回 null 或 new ArrayList<>(),应返回 Collections.emptyList()

    说明Collections.emptyList()返回一个不可变的静态列表。

  9. 【推荐】 类内方法定义的顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter方法。

    说明:公有方法是类的调用者和维护者最关心的方法,首屏展示最好;保护方法虽然只是子类关心,也可能是“模板设计模式”下的核心方法;而私有方法外部一般不需要特别关心,是一个黑盒实现;因为承载的信息价值较低,所有 Service 和 DAO 的 getter/setter 方法放在类体最后。

(六) 集合处理

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

    1) 只要重写 equals,就必须重写 hashCode。

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

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

  2. 【强制】使用集合转数组的方法,必须使用集合的 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 错误。
  1. 【强制】使用工具类 Arrays.asList() 把数组转换成集合时,不能使用其修改集合相关的方法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。

    说明asList()方法实质调用了 new ArrayList<>(a) 返回一个不可变的 Arrays.ArrayList 内部类。

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

正例:

List<String> list = new ArrayList<>(); 
list.add("1"); list.add("2"); 
Iterator<String> iterator = list.iterator(); 
while (iterator.hasNext()) { 
    String item = iterator.next(); 
    if (删除元素的条件) { 
        iterator.remove(); 
    } 
}

反例:

for (String item : list) { 
    if ("1".equals(item)) { 
        list.remove(item); 
    } 
} 

(七)DAO 规约

  1. 【强制】禁止在 DAO 层定义 store 方法(即插入/更新逻辑都在同一方法处理),应分别定义 insertXXXXupdateXXXX 方法,并在 Service 层处理相关业务逻辑。

  2. 【强制】禁止使用 DAO 的 store 方法插入或更新数据,应显式调用 insertupdate

  3. 【推荐】查询分页时,若 fetchCount 为 0,则直接返回空列表的分页数据,可避免执行后面的分页语句。

  4. 【推荐】查询分页时,应避免使用联表查询,当数据量上万或十万级别时,单表查询的速度会比联表查询分页快2-10倍。

  5. 【推荐】当需要联超过3个以上的表,应考虑拆分成单表查询。

(八)建表规约

  1. 【强制】表必备三字段:id, created_at, updated_at

  2. 【强制】表名、字段名必须使用小写字母或数字,并以下划线分割。

  3. 【强制】表结构修改必须按 Flyway 的版本去更新,禁止直接在旧版本的迁移脚本中修改字段。应由项目负责人定期合并版本。

  4. 【强制】表、字段必须添加注释 COMMENT xxxx,字段名修改时也应该同时更新对应注释。

  5. 【强制】任何字段如果为非负数,必须是 unsigned

  6. 【推荐】字段允许适当冗余,以提高查询性能,但必须考虑数据一致。冗余字段应遵循:

    1)不是频繁修改的字段。

    2)不是 varchar 超长字段,更不能是 text 字段。

(九)数据映射(MapStruct)

  1. 【强制】无需映射的字段,应显式 ignore 声明,避免编译期出现 Warning

    正例:@Mapping(target = "name", ignore = true)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值