JAVA后端|JAVA开发手册笔记

项目组上周发了一个JAVA开发手册文档,阅读了以下并搜集了一些资料,做了一些笔记分享给大家
一、编程规约 (一)命名风格
前期基础知识

  • POJO:Plain Ordinary Java Object,简单普通java对象, POJO 是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO。
  • PO:Persistant Object,持久化对象
  • DTO:Data Transfer Object,数据传输对象,xxxDTO,xxx 为业务领域相关的名称。
  • DAO:Data Access Object,数据访问对象
  • BO:Business Object,业务对象
  • VO:Value Object/View Object,值对象,xxxVO,xxx 一般为网页名称。
  • AO:Application Object,应用对象
JAVA后端|JAVA开发手册笔记
文章图片

  1. 下划线或美元符号不能作为命名的开头或结束
  2. 英文和中文拼音不能混合
  3. 类名使用UpperCamelCase
  4. 方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格
  5. 常量命名大写MAX_STOCK_COUNT
  6. 抽象类命名使用Abstract或Base开头,异常类名使用Exception结尾
  7. POJO类中布尔类型的变量都不要加is前缀,否则部分框架会引起序列化错误。
  8. 包名统一使用小写
  9. 局部变量避免采用完全相同的命名
  10. 设计模式体现在命名中
  11. 接口方法属性不用加修饰符号
  12. 枚举类名后带上Enum后缀,枚举成员名称需要全大写
  13. 各层次命名规约
    • Service/DAO层方法命名规约
      • 获取单个对象的方法用get做前缀
      • 获取多个对象的方法用list做前缀,复数结尾,如,listObjects
      • 获取统计值的方法用count做前缀
      • 插入的方法用save/insert做前缀
      • 删除的方法用remove/delete做前缀
      • 修改的方法用update做前缀
    • 领域模型命名规约
      • 数据对象:xxxDO,xxx即为数据表名
      • 数据传输对象:xxxDTO,xxx为业务领域相关的名称
      • 展示对象:xxxVO,xxx一般为网页名称
      • POJO 是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO
(二)常量定义
  1. 常量必须预先定义(不允许任何魔法值)
  2. long型赋值数值后跟大写字母L
  3. 变量值在一个固定范围内变化用enum类型来定义
(三)代码格式
  • public static void main(String[] args) { // 缩进 4 个空格 String say = "hello"; // 运算符的左右必须有一个空格 int flag = 0; // 关键词 if 与括号之间必须有一个空格,括号内的 f 与左括号,0 与右括号不需要空格 if (flag == 0) { System.out.println(say); } // 左大括号前加空格且不换行;左大括号后换行 if (flag == 1) { System.out.println("world"); // 右大括号前换行,右大括号后有 else,不用换行 } else { System.out.println("ok"); // 在右大括号后直接结束,则必须换行 } }

  • 注释的双斜线与注释内容之间有且仅有一个空格
  • 在进行强制类型转换时,右括号与强制转换值之间不需要空格隔开例int a = 1; char b = (int)a;
  • StringBuilder sb = new StringBuilder(); // 超过 120 个字符的情况下,换行缩进 4 个空格,并且方法前的点号一起换行 sb.append("yang").append("hao")... .append("chen")... .append("chen")... .append("chen");

  • 参数逗号后应该加空格
  • IDE的中文件的换行符使用Unix格式
(四)OOP规约
  1. 静态变量或方法直接调用类名访问
  2. 所有重写的方法添加@Override注解
  3. 接口过时需要加@Deprecated注解
  4. Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。
  5. 整型包装类的对象值之间的比较用equals方法
  6. 浮点数不能做==判断,要用误差函数,误差在某一个范围内贼认定两浮点数相等
  7. 包装型数据用compareTo方法判断,equals方法会比较精度
  8. 将Double转换为BigDecisimal例子:BigDecimal recommend1 = new BigDecimal("0.1"); BigDecimal recommend2 = BigDecimal.valueOf(0.1); ,使用valueOf
  9. 类内方法定义的顺序依次是:公有方法或保护方法 > 私有方法 > getter / setter方法。
  10. 字符串的连接使用StringBuffer的append方法
  11. POJO类属性必须使用包装数据类型,必须重现toString方法,不要设定任何属性的默认值,不能同时存在对应属性的isXxx()和getXxx()方法
  12. setter方法中参数名称与类成员变量名称一致,getter、setter不要增加业务逻辑
  13. 类的访问控制(private、public、protected)
(五)日期时间
  1. 时间M,m,H,h的大小写问题
  2. 日期闰年二月问题,枚举类的取值问题
(六)集合处理
  1. 判断集合为空使用isEmpty
  2. 只要覆写 equals,就必须覆写 hashCode。
  3. 空指针异常问题
  4. subList是ArrayList的一个视图,不是ArrayList类
  5. 集合转数组使用toArray(T[] array)
  6. 泛型转化需要用instance of判断
  7. 扩展说一下 PECS(Producer Extends Consumer Super)原则:第一、频繁往外读取内容的,适合用
    。第二、经常往里插入的,适合用
  8. 高度注意 Map 类集合 K/V 能不能存储 null 值的情况,如下表格
    集合类 Key Value Super 说明
    Hashtable 不允许为null 不允许为null Dictionary 线程安全
    ConcurrentHashMap 不允许为null 不允许为null AbstractMap 锁分段技术
    TreeMap 不允许为null 允许为null AbstractMap 线程不安全
    HashMap 允许为null 允许为null AbstractMap 线程不安全
  9. Set元素唯一,可以快速对一个集合去重
(七)并发处理
  1. 获取单例对象保证线程安全
  2. 注意加锁顺序以免出现死锁
  3. 高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。
  4. 上锁在try之前,解锁在finally中
  5. 并发修改数据时,要加锁,要么在应用层加锁,要么在缓存加锁,要么在数据库曾使用乐观锁,使用version作为更新依据
    • 乐观锁:在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。
    • 悲观锁:在修改数据之前先锁定,再修改的方式被称之为悲观并发控制,分为共享锁和拍他锁。
  6. 资金相关的金融敏感信息使用悲观锁策略:一锁、二判、三更新、四释放
  7. Random线程安全,但是会导致性能下降
(八)控制语句
  1. switch语句必须拥有default
  2. switch的括号中的数据类型为String时,必须进行null判断
  3. if/else/for/while/do语句中必须使用大括号
  4. 三目运算符的NPE拆箱异常
  5. 高并发场景避免用等于作为判断中断的条件
  6. 在判断语句外声明变量描述一个较为复杂的判断表达式
(九)注释规约
  1. 类注释统一使用javadoc方式
  2. 所有抽象方法必须要用javadoc注释
  3. 所有的类必须添加创建者和创建日期
  4. 方法注释与代码对齐
  5. 所有枚举类型都需要有注释
  6. 代码和注释更改同步
  7. //TODO和//FIXME
(十)前后端规约
  1. 减少null的返回
  2. 服务端发生错误需要给前端的响应信息包括:HTTP状态码、errorCode、errorMessage、用户信息提示四个部分,JSON数据格式为lowerCamelCase风格
  3. 超大整数返回使用String字符串,浮点数会存在精度损失
  4. 服务端返回数据使用JSON,前后端时间格式同意使用“yyyy-MM-dd HH:mm:ss”,统一为GMT
(十一)其他
  1. random()使用如果要取整,需要将Random对象的nextInt或nextLong方法
  2. 后台输送给页面的变量必须加$!{var}——中间的感叹号。
二、异常日志 (一)错误码
  1. 全部正常但是不得不填充错误码时返回00000
  2. 错误码的后三位编号与 HTTP 状态码没有任何关系
  3. 错误码有利于不同文化背景的开发者进行交流与代码协作
(二)异常处理
  1. finally中不使用return
  2. 尽量避免NPE的产生
(三)日志规约
  1. 尽量使用SLF4J,JCL-Jakarta Commons Logging中的API
  2. 生产环境禁止直接使用 System.out 或 System.err 输出日志或使用e.printStackTrace()打印异常堆栈
  3. 异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过关键字 throws 往上抛出。
三、单元测试
  1. AIR原则:自动化、独立性、可重复
  2. 单元测试的粒度要足够小,有助于精确定位,一般是方法级别
  3. 测试代码写在src/test/java目录下
  4. 单位测试代码遵守BCDE原则:Border、Correct、Design、Error
四、安全规约 用户的数据获取或链接跳转、评论信息等需要安全过滤的操作需要受到安全规约
五、MySQL数据库 (一)建表规约
  1. is_XXX命名
  2. 表名和字段名必须使用小写字母或者数字,禁止出现数字开头
  3. 表名不适用复数名词
  4. 不使用保留字
  5. 主键索引名为pk_xxx,唯一索引名为uk_xxx,普通索引名为idx_xxx
  6. 小数类型为decimal
  7. 存储的字符串长度几乎相等可以使用char定长字符串类型
  8. 表必备的三个字段:id,create_time,update_time
  9. 合适的字符存储长度,例如无符号类型数值
(二)索引规约
  1. 三个表禁止join
  2. varchar字段索引必须指定索引长度
(三)SQL语句
  1. 不要使用count(列名)代替count(*)
  2. 当某一列全为NULL,sum()返回NULL,所以要注意NPE问题
  3. 判断NULL用ISNULL()方法
  4. 禁止使用存储过程
  5. 数据修改时要先使用select选择更新语句
  6. 表的别名用as + t1、t2、t3…的顺序依次命名
(四)ORM映射
  1. sql.xml配置参数使用#{},#param不要使用${}
  2. 不允许直接拿HashMap与HashTable作为查询结果集的输出
  3. 更新据表要更新update_time字段为当前时间
  4. @Transactional事务不要滥用
六、工程结构 (一)应用分层
【JAVA后端|JAVA开发手册笔记】JAVA后端|JAVA开发手册笔记
文章图片

(二)二方库依赖
  1. GAV:GroupID格式:com.{公司}.业务线[.子业务线];ArtifactID格式:产品线名-模板名;Version:参考下方
  2. 版本命名:主版本号.次版本号.修订号
  3. 禁止在子项目的pom依赖中出现相同的GroupId,相同的ArtifactId,但是不同的Version
(三)服务器
  1. 高并发的服务器建议调小TCP协议的time_wait超时时间
  2. 服务器内部重定向必须使用 forward;外部重定向地址必须使用 URL Broker 生成,否则因线上采用 HTTPS 协议而导致浏览器提示“不安全“。此外,还会带来 URL 维护不一致的问题。
七、设计规约
  1. 在需求分析阶段,如果与系统交互的 User 超过一类并且相关的 User Case 超过 5 个,使用用例图来表达更加清晰的结构化需求。
  2. 如果某个业务对象的状态超过 3 个,使用状态图来表达并且明确状态变化的各个触发条件。
  3. 总之设计时要遵循设计本身的各种规约

    推荐阅读