java开发规范其实有很多内容的,在这里我只选一些我认为比较重要或者比较容易忽略的部分,主要是有点懒,大家别见怪啊。
A) Service/DAO 层方法命名规约
1) 获取单个对象的方法用 get 做前缀。
2) 获取多个对象的方法用 list 做前缀。
3) 获取统计值的方法用 count 做前缀。
4) 插入的方法用 save(推荐)或 insert 做前缀。
5) 删除的方法用 remove(推荐)或 delete 做前缀。
6) 修改的方法用 update 做前缀。
B) 领域模型命名规约
1) 数据对象:xxxDO,xxx 即为数据表名。
2) 数据传输对象:xxxDTO,xxx 为业务领域相关的名称。
3) 展示对象:xxxVO,xxx 一般为网页名称。
4) POJO 是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO。
如果是大括号内为空,则简洁地写成{}即可,不需要换行;如果 是非空代码块则:
1) 左大括号前不换行。
2) 左大括号后换行。
3) 右大括号前换行。
4) 右大括号后还有 else 等代码则不换行;表示终止右大括号后必须换行。
左括号和后一个字符之间不出现空格;同样,右括号和前一个字符之间也不出现空格。详见第 5 条下方正例提示。
【强制】if/for/while/switch/do 等保留字与左右括号之间都必须加空格。
【强制】任何运算符左右必须加一个空格。 说明:运算符包括赋值运算符=、逻辑运算符&&、加减乘除符号、三目运行符等。
【强制】代码块缩进 4 个空格,如果使用 tab 缩进,请设置成 1 个 tab 为 4 个空格。
如下:
1) 所有的 POJO 类属性必须使用包装数据类型。
2) RPC 方法的返回值和参数必须使用包装数据类型。
3) 所有的局部变量推荐使用基本数据类型。
依次是:公有方法或保护方法 > 私有方法 > getter/setter 方法。
说明:公有方法是类的调用者和维护者最关心的方法,首屏展示最好;保护方法虽然只是子类关心,也可能是“模板设计模式”下的核心方法;而私有方法外部一般不需要特别关心,是一个黑盒实现;因为方法信息价值较低,所有 Service 和 DAO 的 getter/setter 方法放在类体最后。
在 if/else/for/while/do 语句中必须使用大括号,即使只有一行代码,避免使用下 面的形式:if (condition) statements;
, if-else 的方式可以改写成:
if(condition){
…
return obj;
}
// 接着写 else 的业务逻辑代码;
说明:如果使用要 if-else if-else 方式表达逻辑,请勿超过 3 层,超过请使用状态设计模式。
10.1类、类属性、类方法的注释必须使用 javadoc 规范,使用/*内容/格式,不得使用 //xxx 方式。
说明:在 IDE 编辑窗口中,javadoc 方式会提示相关注释,生成 javadoc 可以正确输出相应注释;在 IDE 中,工程调用方法时,不进入方法即可悬浮提示方法、参数、返回值的意义,提高阅读效率。
10.2所有的抽象方法(包括接口中的方法)必须要用 javadoc 注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。
说明:如有实现和调用注意事项,请一并说明。
10.3所有的类都必须添加创建者信息。
后台输送给页面的变量必须加 !var——中间的感叹号。说明:如果var=null或者不存在,那么 {var}会直接显示在页面上。
Math.random() 这个方法返回是 double 类型,注意取值范围
0≤x<1(能够取 到零值,注意除零异常),如果想获取整数类型的随机数,不要将 x 放大 10 的若干倍然后取整,直接使用 Random 对象的 nextInt 或者 nextLong 方法。
获取当前毫秒数:System.currentTimeMillis(); 而不是 new Date().getTime(); 说明:如果想获取更加精确的纳秒级时间值,用 System.nanoTime。在 JDK8 中,针对统计时间等场景,推荐使用 Instant 类。
防止 NPE,是程序员的基本修养,注意 NPE 产生的场景:
1) 返回类型为包装数据类型,有可能是 null,返回 int 值时注意判空。
反例:public int f(){ return Integer 对象},如果为 null,自动解箱抛 NPE。
2) 数据库的查询结果可能为 null。
3) 集合里的元素即使 isNotEmpty,取出的数据元素也可能为 null。
4) 远程调用返回对象,一律要求进行 NPE 判断。
5) 对于 Session 中获取的数据,建议 NPE 检查,避免空指针。
6) 级联调用 obj.getA().getB().getC();一连串调用,易产生 NPE。
避免出现重复的代码(Don’t Repeat Yourself),即 DRY 原则。
说明:随意复制和粘贴代码,必然会导致代码的重复,在以后需要修改时,需要修改所有的副本,容易遗漏。必要时抽取共性方法,或者抽象公共类,甚至是共用模块。
正例:一个类中有多个 public 方法,都需要进行数行相同的参数校验操作,这个时候请抽取:
private boolean checkParam(DTO dto){...}
如打点、临时监控、访问日志等:
appName_logType_logName.log。logType:日志类型,推荐分类有 stats/desc/monitor/visit等;logName:日志描述。这种命名的好处:通过文件名就可知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找。
正例:mppserver 应用中单独监控时区转换异常,如:
mppserver_monitor_timeZoneConvert.log
说明:推荐对日志进行分类,错误日志和业务日志尽量分开存放,便于开发人员查看,也便于通过日志对系统进行及时监控。
输出的 POJO 类必须重写 toString 方法,否则只输出此对象的 hashCode 值(地址值),没啥 参考意义。
必须使用小写字母或数字;禁止出现数字开头,禁止两个下划线中间只 出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。
正例:getter_admin,task_config,level3_name
反例:GetterAdmin,taskConfig,level_3_name
唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。 说明:uk_ 即 unique key;idx_ 即 index 的简称。
表必备三字段:id, gmt_create, gmt_modified。 说明:
其中 id 必为主键,类型为 unsigned bigint、单表时自增、步长为 1;分表时改为从TDDL Sequence 取值,确保分表之间的全局唯一。gmt_create, gmt_modified 的类型均为date_time 类型。
合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检索速度。
正例:人的年龄用 unsigned tinyint(表示范围 0-255,人的寿命不会超过 255 岁);海龟就必须是 smallint,但如果是太阳的年龄,就必须是 int;如果是所有恒星的年龄都加起来,那么就必须使用 bigint。
计算该列除 NULL 之外的不重复数量。注意 count(distinct col1, col2) 如果其中一列全为 NULL,那么即使另一列有不同的值,也返回为 0。
使用 ISNULL()来判断是否为 NULL 值。注意:NULL 与任何值的直接比较都为 NULL。
说明:
1) NULL<>NULL 的返回结果是 NULL,不是 false。
2) NULL=NULL 的返回结果是 NULL,不是 true。
3) NULL<>1 的返回结果是 NULL,而不是 true。
在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。 说明:
1)增加查询分析器解析成本。
2)增减字段容易与 resultMap 配置不一致。
xml 配置中参数注意使用:#{},#param# 不要使用${} 此种方式容易出现 SQL 注入。
事务会影响数据库的 QPS,另外使用事务的地方需要 考虑各方面的回滚方案,包括缓存回滚、搜索引擎回滚、消息补偿、统计修正等。
即使所有类属性名与数据库字段一一对应,也需要 定义;反过来,每一个表也必然有一个与之对应;
不允许直接拿 HashMap 与 HashTable 作为查询结果集的输出。
说明:配置映射关系,使字段与 DO 类解耦,方便维护。
反例:某同学为避免写一个,直接使用 HashTable 来接收数据库返回结果,结果出现日常是把 bigint 转成 Long 值,而线上由于数据库版本不一样,解析成 BigInteger,导致线上问题。