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