个人经验

Controller层:全部使用包装类型!

Service层:全部使用包装类型!

Mapper层:返回值必须使用包装类型!

Pojo层:字段必须使用包装类型!

为什么使用包装类型,因为用户传参,可能会为null,数据库select的结果可能是null,即便数据库select的结果不是null,Pojo实际接收的字段,你无法保证是否为null!

如果需要参数校验,String类型必须使用StringUtils.isNotBlank(XXXX) 处理!

命名规范

  • 包名:
    • 全部小写
  • 类名、接口名:
    • 大驼峰AaaAaa
  • 方法名、局部变量:
    • 小驼峰 aaaAAA
  • 成员变量:
    • 小驼峰 aaaAAA
  • 枚举
    • 全部大写

其他场景

Abc的测试类命名为:AbcTest

包名在有且仅有一个正常语义单词的情况下,包名单数,类名复数含义可以使用复数

com.zanglikun.testDemo.util
其包下的类名建议用复数
StringUtils

不推荐使用尚未明确定义的值

 String magicValue = "pilipala_" + account;
 不推荐的理由:比如账号是789
 pilipala_789 容易被写成pilipala789

long类型不允许使用小写l 必须使用大写L

 Long timeStamp = 1L;
 
 反例:Long timeStamp = 1l; 这样定义容易被别人理解成11

注释规范

注释类型

  • 单行注释 // 必须用于方法体上一行
  • 多行注释 /* */ 常用于类名、方法名、类属性、接口 必须使用Javadoc规范,除了基本介绍参数、返回值信息,最好声明:方法是干什么的
  • @see 用法
  • todo 用法
/**
* @see  #b() 
* 请参考其他方法b Ctrl+ 鼠标左键点击即可
*/
 public void a(){
 }

 public void b(){
    // todo 这里需要做XXX逻辑
 }

单行注释:注释符与注释正文之间:有且只能有一个空格!

// 我是注释
反例://我是注释

接口、抽象类必须使用Javadoc文档规范,不得使用//

数组命名

推荐:int[] userList;
而不是 int userList[];

强转类型:右括号强制与转换至中间无空格

int account = 1234;
String magicValue = (String)abc;

IDEA设置:

  • text file encoding 设置成UTF-8
  • 文件换行符:设定为Unix,不要使用Windows

POJO类不要加is前缀:这里有些框架会引起序列化错误

 // 定义一个变量,命名为:isDeleted
 private boolean isDeleted;

 // 然后 Alt + Insert 然后getter/setter一下
 public boolean isDeleted(){
     return isDeleted;
 }

 public void setDeleted(boolean deleted){
     this.isDeleted = deleted;
 }

=================================================================

 // 再次定义一个变量,命名为:Deleted
 private boolean Deleted;

 // 然后 Alt + Insert 然后get set一下
 public boolean isDeleted(){
     return isDeleted;
 }

 public void setDeleted(boolean deleted){
     this.isDeleted = deleted;
 }

对比发现,isXXX与XXX在定义成基本类型的时候,默认的属性名是:Deleted。
如果是包装类型 Boolean 则是正常getIsDeleted,与getDeleted

如果数据库表中有is_XXX,建议在mybatis <resultmap> 标签中进行配置。

OOP规约

避免通过类的对象去访问类的静态变量或者静态方法,直接使用类名. 即可

对象在堆中,类信息在方法区。
如果通过对象去访问静态变量:就需要获取对象的方法区,找到类信息,再去找到静态变量的值。
类名. 本身就在方法区,减少编译器的解析成本!

方法重写务必追加@Override,用于检测方法重写:不然无法准确是否是方法重写

方法参数尽量避免使用Object,作为参数类型:可以减少出现类型转换异常,

不建议开发者使用可变参数…编程

@Deprecated 过时 过期方法需要加入此注解

方法过期了,不推荐使用了,请使用@Deprecated注解,并详细建议的使用新方法XXX

同理,不建议使用过期的方法

equals:避免引用类型调用equals,避免出现 空指针异常

 String iPhone = null;
 "abc".equals(iPhone); // 不会有问题
 iPhone.equals("abc"); // 会有空指针异常风险

引入面试题
Integer a = 1;
Integer b = 1;
(a==b) // true

Integer a = 128;
Integer b = 128;
(a==b) // false
Idea Ctrl + 鼠标左键,Ctrl + F 搜索cache 找到
-128到127的单位内,使用的Integer是缓存的数据,此范围之外,才是new一个对象

货币类型:务必以最小的单位整形命名。 23章节

浮点型的等值比较:基本数据类型不能使用 == 包装数据类型不能使用equals()来判断,如下一条有说明

BigDecimal 等值强制使用compareTo()方法,而不是equals()方法,equals 方法会比较精度 ((1.0).equals(1.00) 就会报错

禁止使用构造方法 BigDecimal(duble)的方式将double转为BigDecimal对象,会有精度损失,而建议使用

BigDecimal g = new BigDecimal(string); 
如:BigDecimal g = new BigDecimal("0.1");
因为BigDecimal的valueOf()是执行了Double的toString方法,所以valueOf也是能用的
BigDecimal g = BigDecimal.valueOf(0.1d);

定义数据类型DO 也就是与数据库对应的类型,属性类型,与字段类型要匹配

如果数据库字段money是bigint类型,创建Java类型字段不能使用
Integer money; // Integer范围大约是正负21亿,随着业务增长,java的Integer类型无法满足范围了
Long money; // 范围则会更一些。

所有POJO的数据类型务必使用包装类型,且使用时,务必保证NPE 也就是空指针异常的处理

所有的PRC方法的返回值必须使用包装类型

定义DO/DTO/VO/POJO不能设置默认值

比如日期字段:数据库查出来时空,你初始化了默认值,容易起业务争议

序列化类新增属性的时候,不要修改seriaVersionUID字段,避免反序列化失败。

构造方法,禁止写业务逻辑,如果有初始化逻辑,请自定义init()方法中

日期的正常格式 yyyy-MM-dd HH:mm:ss

M是月份
m是分钟
H是24小时进制
h是12小时进制

获取毫秒,务必使用System.currentTimeMillis(),而不是new Date.time()。创建对象,总归要慢一些。

程序不仅要写死一年时365天,避免公历闰年时出现日期转换错误

正确请使用:
// 获取今年的天数
int dayOfThisYear = LocalDate.now().lengthOfYear();

// 获取某年的天数
LocalDate.of(2011,1,1).lengthOfYear();

集合

https://www.zanglikun.com/2301.html#face

判断集合是否时空,使用isEmpty(),而不是获取size再去判断==0的情况;

List集合转Map的方式,必须使用 下面方法,尚未补全P39

List

已跳过集合知识

线程

线程资源必须通过线程池提供,不允许应用自行显示创建线程。原因:创建大量线程导致OOM或内存切换导致性能下降。

创建线程,必须使用new ThreadPoolExecutor(…) 可以快速了解线程池的配置信息,需要复习本站的线程池知识

高并发时,能锁方法块,就不要锁完整方法体

加锁,加在try之外,释放锁必须在finally里面

控制语句

switch 务必追加 defult!

高并发情况下:使用 == 容易造成等于击穿的情况:比如奖品数量==0,然后返回。一旦==的判断值为复数,则后续的值,就跳过了奖品数量为0的判断了,建议使用>=0 或者<=0

前后端规范

后端接口必须使用Https

后端返回信息必须包含:1:Http状态码、2:错误码、3:错误信息、4:用户提示信息

后端返回给前端数字类型一律:String类型

Http请求:需要限制请求体Body大小。

前后端分页:要动态处理:规范分页参数有效

错误码

错误码:A0001与错误日志需要清晰明了

正确错误码:00000,必须传递

错误码由字母 + 4位编号组成。A代表用户错误、B服务端错误,C代表第三方错误。

错误码与错误信息不得反馈给用户!

异常日志

异常能提前避免,就提前避免:比如随便加些判断,避免空指针等情况

异常是为了处理,不是为了抛出去,必须有方法兜底去处理,不得被用户看到

事务控制中,如果自行catch了异常,请手动回滚事务

try 里面的return不会立即返回,必须finally走完,如果finally有return,则会抛弃try里面的

在调用RPC相关方法时,catch必须使用Throwable类来拦截

日志规约

使用日志框架,不要直接使用日志系统。推荐使用slf4j日志框架

日志文件建议保存15天。如:周一报错,其他时间不报错,就需要以周进行拦截与查看了。

对于网络运行状态、网络安全事件、个人敏感操作不少于6个月。国家规定

强烈推荐{} 占位符,因为字符串拼接使用append有性能损耗,占位符只是替换,性能更优

避免日志重复打印,务必在日志配置文件中设置additivity=false

生产环境禁止使用System.out或者 System.err 输出日志。

日志输出参数的时候,禁止使用JSON工具,因为JSON工具获取对象属性是get,如果get报错,那就麻烦了。推荐对象toString()

安全规约

用户敏感数据,必须要脱敏

防止SQL注入

防止XSS注入

用户传入任何参数都需要校验!

JAVA CSRF安全验证

对短信、右键等进行数量、疲劳、验证码校验。避免资源被滥刷

MySQL数据库

是否概念必须使用is_xxx命名unsigned tinyint 1表示是,0表示否。unsigned表示非负数

POJO类中任何与布尔类型的变量不得使用is前缀,使用mybatis中resultmap标签进行映射

主键命名pk_字段名,唯一索引名 uk_字段名,普通索引名idx_字段名

表必备按字段id,create_time,update_time

唯一索引是一定的约束

超过三张表禁止join,需要join字段数据类型绝对保持一直(避免索引失效),关联字段必须有索引

varchar建立索引必须指定长度,但不建议全部程度。这里建议百度一下!

不得使用左模糊、全模糊,如果有业务使用,使用搜索引擎

count(*) 与 count(1) 区别是 *会扫描null,但是1则查询非空的数量

不得使用外键

禁止使用存储过程

数据修改,一定要查一下,看一下是否是自己的要修改的

多表查询,必须使用别名

ORM映射

不得使用 * 作为查询的字段列表,容易引起与resultmap不一致。同时也会造成不必要的网络资源浪费,比如用不到的text的内容等等

任何返回必须定义一个ResultMap,不得直接返回Class

更新表记录时,必须更新对应的update_tiem字段为敌当前时间

不得使用HashMap或HashTable作为结果集返回。容易出现字段类型范围不匹配的问题