1. 规范: 语法规范
1.1. 命名规范
【推荐】业务属性:对象、方法命名,要使用携带业务属性的名词,比如AdvertVO;反例DeleteVO;除非单纯对该对象操作,而对象具备了名词意义,比如AdvertVO中包含方法,getAccountByVO(AdvertVO advertVO)
【强制】代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式
说明: 正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使是纯拼音命名方式也要避免采用。
正例: alibaba / tabao / youku / hangzhou / duiba / tuia 等国际通用的名称,可视同英文
反例: DaZhePromotion [ 打折] / getPinFenByName ( ) [ 评分] / int 某变量 = 3
【强制】对象中禁止使用 同名&大小写不一致 的字段
说明: JAVA本身是支持对象中同名且大小不一致的字段,但是第三方工具对这种形式的命名不友好,甚至异常报错。例如fastjson、jackson、lombok等
正例: name & otherName / age & otherAge / sex & otherSex
反例: name / NAME
【强制】类名使用UpperCamelCase风格,但 DO/BO/DTO/VO/AO/PO 等情形例外。
正例: MarcoPolo / UserDO / XMLService / TcpUdpDeal / TaPromotion / Qrcode
反例: macroPolo / UserDo / XmlService / TCPUDPDeal / TAPromotion / QRcodeg
案例: DTO == > DO 入库,不用严格执行,对于下游系统直接可以DTO入库(松懈)
强制: DTO作为RPC的载体,必须实现序列化,此外类属性杜绝使用 BigDecimal (原因自行百度)
中台部门ext包支持启动检索,在启动类Application的main方法第一行加入代码扫描指定文件夹:
cn. com. duiba. wolf. utils. ClassUtils. checkDto ( "cn.tuia.activity.center.api.dto" ) ;
【强制】系统交互单位处理(图片、视频大小),统一用 KB 进行交互和计算,如果涉及前端数据量过大需要转换成 MB 等,只是修改前端显示处理
【推荐】前后端字段命名,接口交互采用swagger生成的接口文档导入yapi使用
1. 兑吧yapi地址:http: / / yapi. dui88. com/
2. 上传swagger== > 【数据管理】== > 开启url导入== > 本地启动web系统
3. 导入swagger地址为本地ip如,http: / / 172.16 .61 .240 : 17785 / v2/ api- docs
4. 运行可以sso_ticket:test和csrf_off:true 绕过权限不要adminId信息
5. yapi对于后端可以用来模拟请求,类似POSTMAN,对于前端有个Mock接口
1.2. 常量变量
【强制】杜绝使用魔法值,尽量使用枚举;每个字段都要进行注释;任何常量、硬编码都要注释,当前意义和剩余的其他意义;字段的命名(尤其是大数据日志type类型)最好使用【元数据管理系统】data-dictionary,注册字段和意义,系统会自动生成枚举Jar包,然后升级工程依赖版本号,全司统一
正例:
@Getter
public enum OrientPeopleTagTypeEnum {
NONE ( 0 , "无" ) ,
CROWDINTEREST ( 1 , "商业兴趣标签" )
;
private Integer type;
private String desc;
OrientPeopleTagTypeEnum ( Integer type, String desc) {
this . type = type;
this . desc = desc;
}
。。。。
}
注意:类属性要注释,类属性要生成getter方法
1.3. OOP规约
面向对象6大原则: SRP、OCP、LSP、DIP、ISP、LOD
Single Responsibility Principle、Open Close、 Liskov Substitution、 Dependence Inversion、Interface Segregation、 Law of Demeter
【强制】静态变量或静态方法类名直接调用,避免使用实例对象调用,造成无谓的加编译器解析成本,直接用类名访问即可。
【强制】所有覆盖方法,必须加@Override注解
说明: getObject ( ) 与 get0bject ( ) 的问题。一个是字母0 , 一个是数字 0 ,加@Override 可以准确判断是否覆盖成功。
另外,如果在抽象类中对方法签名进行修改,其实现类会马上编译报错;类似的常量赋值时要用大写的L,反例如Long a = 2 l和数字Long a = 21
【强制】Object的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用equals
正例: "test" . equals ( object)
反例: object. equals ( "test" )
说明: 推荐使用java. util. Objects#equals ( JDK7 引入的工具类)
Objects. equals ( "test" , "testNo" ) ;
【强制】大坑!!!所有相同类型的包装类对象之间的比较,全部使用equals方法。
说明: 对于 Integer var = ? 在 - 128 ~ 127 范围内的赋值,Integer 对象是在 IntegerCache. cache
中产生的,会复用已有对象,这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象。
这是一个大坑,推荐使用 equals 方法进行判断
反例:
Integer a = 122 ;
Integer b = 122 ;
System. out. println ( a == b) ;
Integer c= 129 ;
Integer d = 129 ;
System. out. println ( c == d) ;
【强制】关于基本数据类型与包装数据类型的使用标准如下
1. 所有的POJO类属性必须使用包装类型数据
2. RPC 方法的返回值和参数必须使用包装数据类型
3. 所有局部变量使用基本数据类型
说明: POJO类属性没有初值,是要提醒使用者在需要使用时,必须自己显式地进行赋值,
任何NPE问题,或者入库检查,都由使用者来保证
正例: 数据库的查询结果可能是null,因为自动拆箱,所以用基本数据类型接收有NPE风险。采用Integer i
反例: 比如显示成交总额涨跌情况,即正负x% ,x为基本数据类型,rpc失败,默认返回为0 % 不合理,
应该是中画线。所以包装数据类型的 null 值,可以表示其他信息,比如rpc远程调用失败,异常退出
【强制】构造方法禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中
【强制】POJO 类必须写 toString 方法。使用IDE中的工具 source> generate toString 时,如果继承了另一个POJO类,注意在前, 加一下 super.toString。
说明: 在方法抛出异常时,可以直接调用 POJO 的 toString ( ) 方法打印其属性值,便于排查问题;当然lombok也可以自己选择使用
@Override
public String toString ( ) {
return ToStringBuilder. reflectionToString ( this ) ;
}
【强制】禁止在 POJO 类中,同时存在对应属性的 xxx 的 isXxx() 和 getXxx() 方法
说明: 框架在调用属性 xxx 的提取方法时,并不能确定哪种方法一定是被优先调用到
1.4. 类中代码
【强制】private方法使用: 只在类中调用的方法,定义为private
【推荐】public方法使用: 方法要用接口继承
【推荐】单个方法总行数不超过80行
说明: 除注释外,方法签名、左右大括号、方法内代码、空行、回车及任何不可见字符的总行数不超过80行
正例: 代码逻辑分清红花和绿叶,个性和共性,绿叶逻辑单独成为额外方法,使主干代码更加清晰;
共性逻辑抽取成共性方法,便于复用和维护
1.5. 常用方法
【推荐】 List 判空,使用 apache 的 CollectionUtils
import org. apache. commons. collections. CollectionUtils;
正例: if ( CollectionUtils. isEmpty ( map) ) {
。。。
正例: if ( CollectionUtils. isNotEmpty ( map) ) {
反例: if ( null== list|| list. size ( ) == 0 ) {
。。。
源码:
public static boolean isEmpty ( Collection coll) {
return ( coll == null || coll. isEmpty ( ) ) ;
}
【推荐】 Map 判空,使用 apache 的 MapUtils
import org. apache. commons. collections. CollectionUtils;
正例: if ( MapUtils. isEmpty ( map) ) {
。。。
正例: if ( MapUtils. isNotEmpty ( map) ) {
。。。
反例: if ( null== map|| map. size ( ) == 0 ) {
。。。
源码:
public static boolean isEmpty ( Map map) {
return ( map == null || map. isEmpty ( ) ) ;
}
【强制】小心集合使用带来的坑点,这个是坑人的没有具体实现的东西
Map< String, String> demoMap = Collections. emptyMap ( ) ;
String test = demoMap. get ( "test" ) ;
if ( null != demoMap && StringUtils. isEmpty ( test) ) {
demoMap. put ( "test" , "test" ) ;
}
报错:UnsupportedOperationException
List< String> list= Collections. EMPTY_LIST;
list. add ( "1" ) ;
【推荐】 String 判空,使用 apache 的 StringUtils
import org. apache. commons. lang. StringUtils;
正例: if ( StringUtils. isBlank ( sthStr) ) {
。。。 比isEmpty多了全空格的处理判断
正例: if ( StringUtils. isEmpty ( sthStr) ) {
。。。
正例: if ( StringUtils. isNotEmpty ( sthStr) ) {
。。。
反例: if ( null== str|| str. length ( ) == 0 ) {
。。。
源码:
public static boolean isEmpty ( String str) {
return str == null || str. length ( ) == 0 ;
}
1.6. 代码坑点
【参考】代码的时间处理,为什么我的眼里常含泪水?
说明:
(1 )月份比实际数字少1 即( 0 - 11 ,5 月获取到的数字是4 )
(2 )当按年与周一起用时需注意年底与年初的周数
(3 )java默认周的第一天是sunday, 在中国Calendar获取的weekday(周一获取是2 ,周日获取是1 )
(4 )时区问题,检查系统的默认时区
(5 )@RefreshScope 使用cglib代理,注意默认构造
(6 )禁止线程间传递HttpServletRequest,HttpServletRequest在请求调用时由tomcat创建,在响应返回时会被tomcat销毁;
若异步子线程传递使用,会出现主线程执行完成销毁HttpServletRequest,子线程报错
https: / / www. jb51. net/ article/ 158192. htm
https: / / blog. csdn. net/ m0_38039437/ article/ details/ 76229486
( 7 ) RPC/ restful接口的出入参对象一定要实现序列化
【参考】HttpServletRequest千万不要传入到子线程中使用。它是请求调用时由tomcat创建,在响应返回时会被tomcat销毁
【参考】生产使用,尤其是C端投放(高响应场景)很少用深拷贝,BeanUtils.copy或者set基本上都是浅拷贝。浅拷贝注意线程安全问题,其中将取出的属性对象,可以set替换,但不能修改,会污染原数据。
1.7. 集合处理
【强制】不要在foreach循环里进行元素的remove/add 操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁
List< String> list = new ArrayList < > ( ) ;
list. add ( "1" ) ;
list. add ( "2" ) ;
list. add ( "3" ) ;
正例:最好使用两个对象,然后进行removeAll操作,以下正例需要自行确认
Iterator< String> iterator = list. iterator ( ) ;
while ( iterator. hasNext ( ) ) {
String next = iterator. next ( ) ;
if ( "3" . equals ( next) ) {
iterator. remove ( ) ;
}
}
正例:list. removeIf ( "3" : : equals) ;
反例:
for ( String item : list) {
if ( "2" . equals ( item) ) {
list. add ( "4" ) ;
}
}
报错:java. util. ArrayList$Itr. checkForComodification ( ArrayList. java: 901 )
说明:参考《码出高效 Java开发手册》,在for 循环中对expectedModCount采用modCount进行赋值。
在进行for 循环时每次都会有判定条件modCount == expectedModCount,当执行完list. add ( "4" ) 之后,
该判定条件返回false 退出循环,然后执行if 语句,结果同样抛出java. util. ConcurrentModificationException 异常
注意:这里list对象发生多线程竞争时,也会报错,要考虑线程安全性,比如guava缓存取出的也会产生竞争
【强制】 慎用Collectors.toMap,key重复或者value为空会报错;使用toMap时一定要添加(oldVal, newVal) -> newVal)处理重复key;value判空一定要处理好(尽量不要用,value处理很麻烦)!!!一定要空值过滤,单独对象判空:.filter(Objects::nonNull) 注意如果属性为value,属性也要判空
说明: list. stream ( ) . collect ( Collectors. toMap. . . . . ) 方法,在key重复或value为null,会抛出RuntimeException
例子:只是解决重复key的问题,IllegalStateException: Duplicate key
List< Student> arrayList = new ArrayList < > ( ) ;
arrayList. add ( new Student ( 1 , "zhangsan1" ) ) ;
arrayList. add ( new Student ( 1 , "zhangsan2"