The World Best ST.

JAVA编程规范整理

字数统计: 2.6k阅读时长: 9 min
2019/04/13 Share

一、编程规约

(一)命名风格

  1. 命名不能以下划线开头
  2. 尽量使用英文进行命名,禁止使用拼音与英文结合,尽量减少纯拼音的命名
  3. 类的命名为大驼峰命名法,即首字母大写以及后面每个词的首字母都大写
  4. 方法名、参数名、成员变量、局部变量统一使用小驼峰命名法,即首字母小写以及后面每个词的首字母都大写
  5. 常量命名全部大写,单词用下划线隔开,需明确表达出意思,命名可以很长
  6. 异常类使用Exception结尾,抽象类使用Abstract或Base开头,测试类以Test结尾
  7. 定义数组时,将中括号与类型紧挨相连,如:String[] array
  8. 定义普通bean时,布尔值的成员变量不要加is前缀,反例:isDeleted
  9. 包名统一使用小写,例:com.cmbhz.controller
  10. 命名是避免忘文不生意的情况
  11. 如果使用了设计模式,则在命名中体现出来有利于理解,例如:OrderFactory
  12. 枚举类名建议带上Enum后缀,实现类用Impl后缀
    • 数据对象命名:xxxDO
    • 数据传输对象:xxxDTO
    • 展示对象:xxxVO

(二)常量定义

  1. 不允许未经定义的常量直接出现在代码中,例如String key = “stgood” + myId;
  2. Long类型初始化时,请使用大写的L
  3. 不同作用的常量类请分类定义,例如:RedisConsts,CacheConsts

(三)代码格式

  1. 如果大括号内为空,不要换行,写成{}
  2. 如果大括号非空,则应当按下方格式输入
1
2
3
if (a == b) { //a和b与括号之间没有空格,if等保留字与括号之间有空格,运算符左右保留空格
//TODO
} //如果还有 else 等代码则不换行;表示终止的右大括号后必须换行
  1. 缩进代码时必须为4个空格,而非tab,如需使用tab键进行缩进,IDEA与Eclipse需进行相关设置
  2. 注释符与注释内容之间需保留一个空格
  3. 单行字符如果超过120个,则需要进行换行,规则如下:
1
2
3
4
5
6
7
StringBuffer sb = new StringBuffer();
sb.append("cmb").append("hz").....
.append("cmb").append("hz").... //第二行及以后相对于第一行缩进4个空格,运算符一起换行
.append("good"); //括号前不允许换行

method(arg1, arg2, arg3,..., //方法调用如果需要换行,在逗号后面换行
argX);
  1. 方法参数在定义与传入时,多个参数逗号后需要保留一个空格,例如:method(a, b, c)
  2. IDE 的 text file encoding 设置为 UTF-8; IDE 中文件的换行符使用 Unix 格式,不要使用 Windows 格式
  3. 不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开来以提升可读性,但不需要多个空格隔开

(四)OOP规约

  1. 避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可
  2. 所有的重写都要加@Override注解
  3. 外部正在调用或者二方库依赖的接口,不允许修改方法签名,避免对接口调用方产生影响。接口过时必须加@Deprecated 注解,并清晰地说明采用的新接口或者新服务是什么
  4. 不能使用过时的类或方法
  5. 使用”test”.equals(Object),而不是Object.equals(“test”)
  6. 所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较
  7. 关于基本数据类型与包装数据类型的使用标准如下:
    • 所有的 POJO 类属性必须使用包装数据类型
    • RPC 方法的返回值和参数必须使用包装数据类型
  8. 序列化类新增属性时,请不要修改 serialVersionUID 字段,避免反序列失败;如果完全不兼容升级,避免反序列化混乱,那么请修改 serialVersionUID 值
  9. 构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中
  10. 类内方法定义的顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter方法
  11. getter与setter方法中不要增加业务逻辑
  12. 循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展
  13. 工具类不允许有 public 或 default 构造方法

(五)集合处理

  1. 关于 hashCode 和 equals 的处理,遵循如下规则:
    • 只要重写 equals,就必须重写 hashCode
    • 因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的对象必须重写这两个方法
    • 如果自定义对象作为 Map 的键,那么必须重写 hashCode 和 equals
  2. 不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁
1
2
3
4
5
6
7
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (删除元素的条件) {
iterator.remove();
}
}
  1. 使用 entrySet 遍历 Map 类集合 KV,而不是 keySet 方式进行遍历,因为keySet遍历了2次,二entrySet之遍历了一次
  2. 高度注意 Map 类集合 K/V 能不能存储 null 值的情况
集合类 Key Value Super 说明
Hashtable 不允许为 null 不允许为 null Dictionary 线程安全
ConcurrentHashMap 不允许为 null 不允许为 null AbstractMap 锁分段技术(JDK8:CAS)
TreeMap 不允许为 null 允许为 null AbstractMap 线程不安全
HashMap 允许为 null 允许为 null AbstractMap 线程不安全
  1. 利用 Set 元素唯一的特性,可以快速对一个集合进行去重操作,避免使用 List 的
    contains 方法进行遍历、对比、去重操作

(六)并发处理

  1. 线程资源必须通过线程池提供,不允许在应用中自行显式创建线程
  2. 高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁
  3. 对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则可能会造成死锁
  4. 避免 Random 实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一seed 导致的性能下降

(七)控制语句

  1. 在 if/else/for/while/do 语句中必须使用大括号,即使只有一行代码
  2. 在高并发场景中,避免使用”等于”判断作为中断或退出的条件
  3. 避免采用取反逻辑运算符,尽量采用正向逻辑,例如:if (x < 123)

(八)注释规约

  1. 类、类属性、类方法的注释必须使用 Javadoc 规范,使用/*内容/格式
标签 描述 示例
@author 表示一个类的作者 @author description
@version 指定类的版本 @version info
@param 说明一个方法的参数 @param parameter-name explanation
@return 说明返回值类型 @return explanation
  1. 所有的类都必须添加创建者和创建日期
  2. 方法内部单行注释,在被注释语句上方另起一行,使用//注释
  3. 与其“半吊子”英文来注释,不如用中文注释把问题说清楚
  4. 所有的枚举类型字段必须要有注释,说明每个数据项的用途
  5. 谨慎注释掉代码。在上方详细说明,而不是简单地注释掉

(九)异常处理

  1. catch 时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的 catch 尽可能进行区分异常类型,再做对应的异常处理
  2. 捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容
  3. finally 块必须对资源对象、流对象进行关闭,有异常也要做 try-catch
  4. 不要在 finally 块中使用 return,如果在finally中增加return则不会执行try中的return
  5. 方法的返回值可以为 null,不强制返回空集合,或者空对象等,必须添加注释充分说明什么情况下会返回 null 值

(十)日志规约

  1. 应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架SLF4J 中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一
  2. 对 trace/debug/info 级别的日志输出,必须使用条件输出形式或者使用占位符的方式
1
2
3
4
5
6
7
8
9
10
正确:
if (logger.isDebugEnabled()) {
logger.debug("Processing trade with id: " + id + " and symbol: " + symbol);
}

正确:
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);

错误(将日志设置成info时还是会占用资源):
logger.debug("Processing trade with id: " + id + " and symbol: " + symbol);
  1. 避免重复打印日志,浪费磁盘空间,务必在 log4j.xml 中设置 additivity=false
  2. 异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过关键字 throws 往上抛出
  3. 生产环境禁止输出 debug 日志;有选择地输出 info 日志
  4. error 级别只记录系统逻辑出错、异常或者重要的错误信息

(十一)安全规约

  1. 用户敏感数据禁止直接展示,必须对展示数据进行脱敏
  2. 用户请求传入的任何参数必须做有效性验证

(十二)其他

  1. 获取当前毫秒数 System.currentTimeMillis(); 而不是 new Date().getTime();
  2. 及时清理不再使用的代码段或配置信息
  3. 在使用平台资源,譬如短信、邮件、电话、下单、支付,必须实现正确的防重放限制,如数量限制、疲劳度控制、验证码校验,避免被滥刷导致资损

参考资料:
阿里巴巴Java开发手册

CATALOG
  1. 1. 一、编程规约
    1. 1.1. (一)命名风格
    2. 1.2. (二)常量定义
    3. 1.3. (三)代码格式
    4. 1.4. (四)OOP规约
    5. 1.5. (五)集合处理
    6. 1.6. (六)并发处理
    7. 1.7. (七)控制语句
    8. 1.8. (八)注释规约
    9. 1.9. (九)异常处理
    10. 1.10. (十)日志规约
    11. 1.11. (十一)安全规约
    12. 1.12. (十二)其他