0
点赞
收藏
分享

微信扫一扫

代码规范强制

双井暮色 2022-03-16 阅读 89

阅读阿里巴巴Java开发手册(嵩山版) 记录一些不熟悉的强制规范

(一) 命名风格

  • 【强制】POJO 类中的任何布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列 化错误。

  • 【推荐】接口类中的方法和属性不要加任何修饰符号(public 也不要加),保持代码的简洁 性,并加上有效的 Javadoc 注释。尽量不要在接口里定义变量,如果一定要定义变量,确定 与接口方法相关,并且是整个应用的基础常量。

    • 接口方法签名 void commit();
      接口基础常量 String COMPANY = "alibaba";
      
  • 【参考】各层命名规约:

    • 1) 数据对象:xxxDO,xxx 即为数据表名。
    • 2) 数据传输对象:xxxDTO,xxx 为业务领域相关的名称。
    • 3) 展示对象:xxxVO,xxx 一般为网页名称。
    • 4) POJO 是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO。

(二) 常量定义

  • 【强制】==在 long 或者 Long 赋值时,数值后使用大写字母 L,==不能是小写字母 l,小写容易跟 数字混淆,造成误解。

(四) OOP 规约

  • 【强制】不能使用过时的类或方法。 (这个有待商榷,有时不得不用)

  • 【强制】Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。

    • 推荐使用 JDK7 引入的工具类 java.util.Objects#equals(Object a, Object b)
      
  • 【强制】任何货币金额,均以最小货币单位且整型类型来进行存储。

  • 【强制】所有整型包装类对象之间值的比较,全部使用 equals 方法比较。

  • 【强制】浮点数之间的等值判断,基本数据类型不能用==来比较,包装数据类型不能用 equals 来判断。

  • 【强制】如上所示 BigDecimal 的等值比较应使用 compareTo()方法,而不是 equals()方法。

  • 【强制】禁止使用构造方法 BigDecimal(double)的方式把 double 值转化为 BigDecimal 对象。 有精度损失

    • 优先推荐入参为 String 的构造方法,或使用 BigDecimal 的 valueOf 方法
  • 【强制】定义 DO/DTO/VO 等 POJO 类时,不要设定任何属性默认值。

(五) 日期时间

  • 【强制】日期格式化时,传入 pattern 中表示年份统一使用小写的 y

    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    
  • 【强制】获取当前毫秒数:System.currentTimeMillis();

  • 【强制】不允许在程序任何地方中使用:1)java.sql.Date。 2)java.sql.Time。 3)java.sql.Timestamp。

  • 【强制】不要在程序中写死一年为 365 天,避免在公历闰年时出现日期转换错误或程序逻辑 错误。

    // 获取今年的天数
    int daysOfThisYear = LocalDate.now().lengthOfYear();
    // 获取指定某年的天数
    LocalDate.of(2011, 1, 1).lengthOfYear();
    
  • 【推荐】使用枚举值来指代月份。如果使用数字,注意 Date,Calendar 等日期相关类的月份 month 取值在 0-11 之间。

(六) 集合处理

  • 【强制】判断所有集合内部的元素是否为空,使用 isEmpty()方法,而不是 size()==0 的方式。

  • 【强制】不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator 方式,如果并发操作,需要对 Iterator 对象加锁。

    List<String> list = new ArrayList<>();
    list.add("1");
    list.add("2");
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
     String item = iterator.next();
     if (删除元素的条件) {
     iterator.remove();
     }
    }
    
  • 【推荐】高度注意 Map 类集合 K/V 能不能存储 null 值的情况,如下表格:

    image-20220315232035234

(七) 并发处理

  • 【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。

  • 【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这 样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

  • 【强制】必须回收自定义的 ThreadLocal 变量,尤其在线程池场景下,线程经常会被复用, 如果不清理自定义的 ThreadLocal 变量,可能会影响后续业务逻辑和造成内存泄露等问题。 尽量在代理中使用 try-finally 块进行回收。

    objectThreadLocal.set(userInfo);
    try {
     // ...
    } finally {
     objectThreadLocal.remove();
    }
    
  • 【强制】高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能 锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。

  • 【强制】在使用阻塞等待获取锁的方式中,必须在 try 代码块之外,并且在加锁方法与 try 代 码块之间没有任何可能抛出异常的方法调用,避免加锁成功后,在 finally 中无法解锁。

    Lock lock = new XxxLock();
    // ...
    lock.lock();
    try {
     	doSomething();
     	doOthers();
    } finally {
     	lock.unlock();
    }
    
  • 【强制】在使用尝试机制来获取锁的方式中,进入业务代码块之前,必须先判断当前线程是否 持有锁。锁的释放规则与锁的阻塞等待方式相同。

    Lock lock = new XxxLock();
    // ...
    boolean isLocked = lock.tryLock();
    if (isLocked) {
     	try {
     		doSomething();
     		doOthers();
     	} finally {
     		lock.unlock();
     	}
    }
    
  • 【强制】并发修改同一记录时,避免更新丢失,需要加锁。要么在应用层加锁,要么在缓存加 锁,要么在数据库层使用乐观锁,使用 version 作为更新依据。

  • 【强制】多线程并行处理定时任务时,Timer 运行多个 TimeTask 时,只要其中之一没有捕获抛 出的异常,其它任务便会自动终止运行,使用 ScheduledExecutorService 则没有这个问题。

  • 【推荐】资金相关的金融敏感信息,使用悲观锁策略。

  • 【强制】在高并发场景中,避免使用”等于”判断作为中断或退出的条件。

(二) 异常处理

  • . 【强制】不要在 finally 块中使用 return。

    private int x = 0;
    public int checkReturn() {
     try {
     	// x 等于 1,此处不返回
     	return ++x;
     	} finally {
     	// 返回的结果是 2
     	return ++x;
     	}
    }
    

(三) 日志规约

  • 【强制】应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架 (SLF4J、JCL–Jakarta Commons Logging)中的 API,使用门面模式的日志框架,有利于维护和 各个类的日志处理方式统一。

    使用 SLF4J:
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    private static final Logger logger = LoggerFactory.getLogger(Test.class);
    
  • 【推荐】谨慎地记录日志。生产环境禁止输出 debug 日志;有选择地输出 info 日志;如果使用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑 爆,并记得及时删除这些观察日志。

    • 大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。记录日志时请思考:这些 日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?

五、MySQL 数据库

  • 【强制】表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint (1 表示是,0 表示否)。

    • 表达逻辑删除的字段名 is_deleted,1 表示删除,0 表示未删除。
  • 【强制】表名不使用复数名词。

  • 【推荐】表的命名最好是遵循“业务名称_表的作用”。

    正例:alipay_task / force_project / trade_config
    
  • 【强制】表必备三字段:id, create_time, update_time

  • 【参考】合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检索 速度。

    image-20220316011048274

(二) 索引规约

  • 【强制】业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。

  • 【强制】超过三个表禁止 join。需要 join 的字段,数据类型保持绝对一致;多表关联查询时, 保证被关联的字段需要有索引。

    • 即使双表 join 也要注意表索引、SQL 性能。
  • 【强制】在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据 实际文本区分度决定索引长度。

  • . 【推荐】利用覆盖索引来进行查询操作,避免回表。

    • 能够建立索引的种类分为主键索引、唯一索引、普通索引三种,而覆盖索引只是一种查询的一种效 果,用 explain 的结果,extra 列会出现:using index。
  • . 【推荐】利用延迟关联或者子查询优化超多分页场景。

    先快速定位需要获取的 id 段,然后再关联:
     SELECT t1.* FROM 表 1 as t1, (select id from 表 1 where 条件 LIMIT 100000,20 ) as t2 where t1.id=t2.id
    
  • 【推荐】SQL 性能优化的目标:至少要达到 range 级别,要求是 ref 级别,如果可以是 consts 最好。

  • .【参考】创建索引时避免有如下极端误解:

    • 1) 索引宁滥勿缺。认为一个查询就需要建一个索引。
    • 2) 吝啬索引的创建。认为索引会消耗空间、严重拖慢记录的更新以及行的新增速度。
    • 3) 抵制惟一索引。认为惟一索引一律需要在应用层通过“先查后插”方式解决。
  • (17)使用TIMESTAMP存储时间(timestamp索引)

  • (14)必须使用varchar(20)存储手机号

举报

相关推荐

0 条评论