兑吧开发规范《源Java手册》

1. 规范: 语法规范

1.1. 命名规范

  1. 【推荐】业务属性:对象、方法命名,要使用携带业务属性的名词,比如AdvertVO;反例DeleteVO;除非单纯对该对象操作,而对象具备了名词意义,比如AdvertVO中包含方法,getAccountByVO(AdvertVO advertVO)
  2. 【强制】代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式
说明: 正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使是纯拼音命名方式也要避免采用。
正例: alibaba / tabao / youku / hangzhou / duiba / tuia 等国际通用的名称,可视同英文
反例:  DaZhePromotion [打折] / getPinFenByName() [评分] / int 某变量 = 3
  1. 【强制】对象中禁止使用 同名&大小写不一致 的字段
说明: JAVA本身是支持对象中同名且大小不一致的字段,但是第三方工具对这种形式的命名不友好,甚至异常报错。例如fastjson、jackson、lombok等
正例: name & otherName / age & otherAge / sex & otherSex
反例: name / NAME
  1. 【强制】类名使用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");
  1. 【强制】系统交互单位处理(图片、视频大小),统一用 KB 进行交互和计算,如果涉及前端数据量过大需要转换成 MB 等,只是修改前端显示处理
  2. 【推荐】前后端字段命名,接口交互采用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. 常量变量

  1. 【强制】杜绝使用魔法值,尽量使用枚举;每个字段都要进行注释;任何常量、硬编码都要注释,当前意义和剩余的其他意义;字段的命名(尤其是大数据日志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
  1. 【强制】静态变量或静态方法类名直接调用,避免使用实例对象调用,造成无谓的加编译器解析成本,直接用类名访问即可。
  2. 【强制】所有覆盖方法,必须加@Override注解
说明: getObject()get0bject() 的问题。一个是字母0, 一个是数字 0,加@Override可以准确判断是否覆盖成功。
     另外,如果在抽象类中对方法签名进行修改,其实现类会马上编译报错;类似的常量赋值时要用大写的L,反例如Long a = 2l和数字Long a = 21
  1. 【强制】Object的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用equals
正例: "test".equals(object)
反例: object.equals("test")
说明: 推荐使用java.util.Objects#equals(JDK7 引入的工具类)
      Objects.equals("test", "testNo");
  1. 【强制】大坑!!!所有相同类型的包装类对象之间的比较,全部使用equals方法。
说明: 对于 Integer var = ?-128~127范围内的赋值,Integer 对象是在 IntegerCache.cache
     中产生的,会复用已有对象,这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象。
     这是一个大坑,推荐使用 equals 方法进行判断
反例:
Integer a = 122;
Integer b = 122;
// 输出  true
System.out.println(a == b);
Integer c= 129;
Integer d = 129;
// 输出 false
System.out.println(c ==d);
  1. 【强制】关于基本数据类型与包装数据类型的使用标准如下
1. 所有的POJO类属性必须使用包装类型数据
2. RPC 方法的返回值和参数必须使用包装数据类型
3. 所有局部变量使用基本数据类型

说明: POJO类属性没有初值,是要提醒使用者在需要使用时,必须自己显式地进行赋值,
      任何NPE问题,或者入库检查,都由使用者来保证
正例: 数据库的查询结果可能是null,因为自动拆箱,所以用基本数据类型接收有NPE风险。采用Integer i
反例: 比如显示成交总额涨跌情况,即正负x%,x为基本数据类型,rpc失败,默认返回为0%不合理,
      应该是中画线。所以包装数据类型的 null 值,可以表示其他信息,比如rpc远程调用失败,异常退出
  1. 【强制】构造方法禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中
  2. 【强制】POJO 类必须写 toString 方法。使用IDE中的工具 source> generate toString 时,如果继承了另一个POJO类,注意在前, 加一下 super.toString。
说明: 在方法抛出异常时,可以直接调用 POJO 的 toString() 方法打印其属性值,便于排查问题;当然lombok也可以自己选择使用
@Override
public String toString() {
   
     return ToStringBuilder.reflectionToString(this);
}
  1. 【强制】禁止在 POJO 类中,同时存在对应属性的 xxx 的 isXxx() 和 getXxx() 方法
说明: 框架在调用属性 xxx 的提取方法时,并不能确定哪种方法一定是被优先调用到

1.4. 类中代码

  1. 【强制】private方法使用: 只在类中调用的方法,定义为private
  2. 【推荐】public方法使用: 方法要用接口继承
  3. 【推荐】单个方法总行数不超过80行
说明: 除注释外,方法签名、左右大括号、方法内代码、空行、回车及任何不可见字符的总行数不超过80行
正例: 代码逻辑分清红花和绿叶,个性和共性,绿叶逻辑单独成为额外方法,使主干代码更加清晰;
     共性逻辑抽取成共性方法,便于复用和维护

1.5. 常用方法

  1. 【推荐】 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());
}
  1. 【推荐】 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());
}
  1. 【强制】小心集合使用带来的坑点,这个是坑人的没有具体实现的东西
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");
  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)月份比实际数字少1(0-115月获取到的数字是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接口的出入参对象一定要实现序列化
  1. 【参考】HttpServletRequest千万不要传入到子线程中使用。它是请求调用时由tomcat创建,在响应返回时会被tomcat销毁
  2. 【参考】生产使用,尤其是C端投放(高响应场景)很少用深拷贝,BeanUtils.copy或者set基本上都是浅拷贝。浅拷贝注意线程安全问题,其中将取出的属性对象,可以set替换,但不能修改,会污染原数据。

1.7. 集合处理

  1. 【强制】不要在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缓存取出的也会产生竞争
  1. 【强制】 慎用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"
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值