分享

一网打尽CodeReview要点(JAVA)

 codingparty 2019-08-17

常规检查

业务

1. 根据需求检查业务逻辑代码是否正确
2. 检查代码是否符合编码规范
3. 检查代码是否存在潜在bug或内存泄露
4. 检查代码是否存在性能瓶颈

常见BUG

1. 空指针异常,如使用对象时为保证其非null
2. 类型转换异常,如强制转换
3. 算术异常,如除数为0
4. 越界异常,如数组越界
5. 内存溢出异常,如栈溢出(递归)、堆溢出等
    例如:递归函数必须有闭环条件即终止条件,或递归层级建议1000以内
6. 对象隐式更新造成业务错误,如更新对象时未考虑其他业务正在使用

检验


1. API入口参数必须有常规及业务性校验
2. JAVA中对象使用之前必须有非空(null)校验,
  注意:在业务流程上有非空校验即可,例如一个对象之前已经做过校验,不做变更的情况下,再次使用则无需校验
3. 数值类型在做除数计算之前必须进行非0校验

编码风格


1. JAVA控制层访问路径,均以小写命名多个单词则以下划线相连,层级保持在5级以内
2. JAVA类名以大驼峰命名(例如:ClassName)
3. 函数及变量名以小驼峰命名(例如:functionName)
4. 常量名以全大写命名多个单词则以下划线相连(例如:NAME_TYPE)
5. 函数参数个数保持在5个以内
6. 函数返回值要以具有业务含义的对象返回,禁止使用Map作为返回值
7. 魔术数字必须以枚举的方式统一定义并描述其业务含义
9. 代码单行长度不易超过100个字符
10. 单个类文件总代码行数不可超过500行,推荐200以内
11. 单行代码不易出现多层括号嵌套,例如:(),{},[]的多层嵌套
12. 字符串比较将常量放在左边,例如 “a”.equals(name)
13. if..else嵌套不可大于3层

异常处理


1. API接口调用、库函数调用、系统服务调用必须进行异常处理或将异常抛至调用者,不可将异常信息吞掉,例如try{//业务处理}catch(Exception e){//不做任何处理}
2. 处理异常禁止如下操作,通过日志工具记录异常信息
    try{//业务处理}catch(Exception e){ e.printStackTrace(); }
3. 禁止异常处理出现在迭代里面,例如:for 、while、 foreach里面

日志规范


1. ERROR 记录造成业务异常的日志,WARN记录不影响业务流程的异常日志,INFO记录业务流程状态日志,DEBUG详细的操作或数据日志
2.  关键业务节点及业务流程发生状态变化时必须记录日志,关键函数或服务调用必须记录日志
3. 统一日志工具,例如:slf4j
4. 统一日志格式,DEBUG,INFO,WARN,ERROR,此四类级别日志
   常规日志,例如:时间 日志级别 业务类型 日志内容
   审计日志INFO级别,记录在控制层,统一日志内容格式,例如:“用户id,业务模块,操作类型,资源名称,发起地址”
5. 日志内容禁止字符串拼接,建议统一以下格式
   logger.debug("illegalCode[{}]'s pattern is null", request.getIllegalCode())
6. 在一个对象中通常只使用一个Logger对象,Logger应该是static final的,只有在少数需要在构造函数中传递logger的情况下才使用private final。
7. 输出Exceptions的全部Throwable信息,因为logger.error(msg)和logger.error(msg,e.getMessage())这样的日志输出方法会丢失掉最重要的StackTrace信息。
8. 不允许记录日志后又抛出异常,因为这样会多次记录日志,只允许记录一次日志。
9. 不允许出现System print(包括System.out.println和System.error.println)语句。
10. 不允许出现printStackTrace。
11. 不允许出现调试用的Systom.out.pritln("")日志
12. 日志性能的考虑,如果代码为核心代码,执行频率非常高,则输出日志建议增加判断,尤其是低级别的输出<debug、info、warn>,至少INFO以下级别必须判断,
    if(logger.isDebugEnabled()){
        logger.debug("illegalCode[{}]'s pattern is null", request.getIllegalCode())
    }

冗余代码


1. 清除冗余导入,例如:import javax.servlet.ServletContext;导入了却没有使用
2. 清除冗余注释代码,即注释掉且不用的代码
3. 清除业务代码中冗余的“main”函数及System.out.println(),如需测试建议在单元测试用测试
4. 重复性代码,若业务功能一致,必须抽离为公共模块
5. 避免冗余的导入,如:import java.util.*;
6.代码逻辑的冗余
    6.1. 业务逻辑上能提前终止的尽量提前终止,避免执行过多的代码,如:
         参数校验-->下载图片-->校验数据是否重复-->保存数据
         以上流程可以改为如下:
         参数校验-->校验数据是否重复-->下载图片-->保存数据

性能


1. 使用合适的数据类型及初始化大小
   例如:
   a. 多字符串的拼接单线程情况下使用StringBuilder
   b. 数据量固定且读操作频繁的话选择数组存储数据
   c. 集合的使用根据实际情况尽量初始化其容量
2. 资源使用完毕及时释放
   例如:
   a. 对象使用完毕,及时给变量赋值为null
   b. IO使用完毕要及时在finally中关闭掉
3. 使用合适的数据处理方式:懒加载,异步和并行处理
4. 使用合适的方式提升响应速度:缓存、队列
5. 使用对象池,处理大量对象创建的问题
6. 数组的拷贝建议使用系统函数System.arraycopy();
7. synchronized、Lock,达到需求加锁的代码范围或对象粒度越小越好,或不适用!
    例如:
    Set<String> recordIds = new HashSet<>()
    String recordIdKey = genKey();
    synchronized (recordIds) {
        if (!recordIds.contains(recordIdKey)) {
            //TODO 1 ...
            //TODO 2 ...
            recordIds.add(recordIdKey);
        }
     }
     方案1:
     Map<String,String> recordIds = new ConcurrentHashMap<>()
     String recordIdKey = genKey();
     if(recordIds.putIfAbsent()!=null){
       //TODO 1 ...
       //TODO 2 ...
     }
    方案2:
        可使用锁池,recordIdKey获取锁之后再操作
8. 迭代(for、foreach、while)嵌套不可大于3层,且在迭代中不可try...catch异常

安全检查

接口

1. 上传资源接口,必须进行资源类型、大小校验(如非必要禁止文件的执行权限)
2. 下载资源接口,必须进行下载目录校验且进行唯一性资源下载限制
3. 直接执行系统指令的API,避免指令拼接的安全隐患

业务


1. 业务层面权限校验,对资源的访问必须有权限的限制

密码


1. 密码规则应数字、字母、特殊字符组合,长度至少大于6位
2. 密码的加密规则尽量使用:AES256+IV
3. 数据库存储及配置文件中的密码应进行加密

SQL


1. sql编码,必须处理sql注入的问题
2. 请求参数必须进行特殊字符的处理(参数进入业务之前)

并发


1.  并发情况下,公共属性、对象、数据必须进行一致性处理(即并发安全处理)

文档检查

注释


1. API接口必须有功能描述,字段必须有业务描述
2. API说明文档必须和实际API接口保持一致
3. 公共函数必须有功能描述,字段必须有业务描述
4. 数据库表必须有功能描述,字段必须有业务描述
5. 常量(编码)必须有业务描述

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多