zoukankan      html  css  js  c++  java
  • 编码规范

    为什么要有编码规范

    编码规范对于程序员而言尤为重要,有以下几个原因:

    • 一个软件的生命周期中,80%的花费在于维护

    • 几乎没有任何一个软件,在其整个生命周期中,均由最初的开发人员来维护

    • 编码规范可以改善软件的可读性,可以让程序员尽快而彻底地理解新的代码

    • 如果你将源码作为产品发布,就需要确任它是否被很好的打包并且清晰无误,一如你已构建的其它任何产品

    为了执行规范,每个软件开发人员必须一致遵守编码规范

    遵循阿里的的编码规范(P3C)

    什么是代码复查(Code Review)?

    • 代码复查又叫“代码审查”,其基本思想是在开发人员编写完自己的代码后,由其他人进行复查,检查代码中存在的问题。

    • p代码复查的一个基本理论是,当越早发现代码存在的缺陷,解决缺陷的代价就越低

    代码复查往往分成以下一个方面进行审查:

    • 代码风格

      • 代码格式
    • 重大缺陷
      • SQL注入问题
      • 性能问题
    • 设计逻辑与思路的审查
      • 代码逻辑控制是否有问题
      • 代码是否与最初的设计存在出入

    代码复查常见问题

    1.代码格式

    • 未安装静态代码检查工具
    • 代码的缩进仍然使用TAB键,而不是空格
    • 未使用快捷键“Ctrl+Shift+F”格式化

    2.代码注释

    • 存在大段代码没有注释的情况,最好有简单的注释说明一下。
    • 程序的重要分支没有注释,分支的注释有利于理解业务逻辑。
    • 代码注释与实现不一致。
    • 代码注释多余或者没有实际意义。
    • 常量注释最好采用多行注释的风格而非单行注释。
      • 说明:这样做的原因是,在IDE中,外部调用常量的地方可以看到注释

    3.命名规范

    • 常量定义问题,很多数字(魔法数字)、字符应该定义为常量,并指定有意义的名称,便于理解和维护

    4.代码结构

    • 程序没有分层的概念
    • 每层的职责要分明
    • 类方法的参数列表过长,应该抽象为一个参数类
    • 存在多层if嵌套和多层while嵌套的情况

    • 无效的引用,代码中存在很多无效的包、类引用,应该去掉没用到的引用,或者使用快捷键CTRL+SHIFT+O重新组织一下导入

    • 无效代码

      • 存在空的方法或者没用到的变量,建议删除。

      • 一些业务处理类的方法参数中有pageNo相关的参数,但是实际上该函数并没有进行分页处理。

      • 复查时,经常看到大段的代码被注释掉,建议删除。 咱们有svn,如果想找到,可以查看svn历史版本。

    第一章 正确性检查

    1. 数据类型处理

    • 定义了一个Integer类型的a,在对a进行switch(a)等操作的时候,没有对a进行判空,导致空指针异常

    • double数字处理时,直接进行加减、比较、零值判断等,可能存在精度问题。正确的判断方式应是约等于零,这个方法可以定义为公用的工具方法。

      Double dValue = …;  
      if(dValue> -0.00001 && dValue< 0.0001) { // 约等于0          // do  something  
      } **else** {   
      //  do others  
      }  
      
    • int类型的数据作除法时要注意,得到的有可能不是想要的结果。

    int iFz= 2;
    int iFm = 3; // 可能为0
    // 错误的做法
    Double present = iFz / iFm; // 实际得到的是0
    *********************
    int iFz= 2;
    int iFm = 3; // 可能为0
    // 正确的做法
    if(iFm != 0) {
       Present = (double)iFz/iFm; // 做强制类型转换
    } else {
       Present = 100;
    }
    
    
    • 字符串判断时,空串和空格串的差异需要注意,apache common包中提供了相关的判断方法。
    String str="";
    if (str != null &&str.length() != 0){
        //do sth
    }
    =====================================================================
    String str="";
    if (StringUtils.isNotBlank(str)){
        //do sth
    }
    
    
    • Equals方法的使用
      • 字符串比较应当使用equals方法。
      • 应该用常量字符串在前,比较变量,避免null错误。
    String str_temp="temp";
    if(str_temp=="test"){
        //do sth
    }
    ******************
    //正确的方法
    String str_temp="temp";
    if("test".equals(str_temp)){
        //do sth
    }
    
    
    • 日期处理时,增加一个月,有代码实现时采用了加30天的做法。应该使用java8里的日期处理类

    • 不应当使用字符串拼接的方式,应该用StringBuffer或者StringBuilder代替

    • 多个数据库操作,没有使用事务(编程式事务、声明式事务)

    • 当发生异常时,一般先回滚事务,然后记录日志或者再抛异常,回滚事务意味着及早释放锁资源,并且防止记录日志时出异常,导致无法回滚。

    try {
        //do sth 
        commit(status);
    } catch (Exception e) {
        rollback(status);//首先回滚事务,释放锁资源
        LOG.error("处理失败:", e);//再记录日志
    }
    
    • 关于分页列表count统计的处理,有很多不合理的代码。

      • Count方法中,用list.size()返回记录条数,这样会把所有的列表数据加载到内存,浪费资源。正确做法是用select count(*)来获取记录条数。

      • 记录日志时避免进行正常业务逻辑的处理,如以下debug操作进行了一次数据库查询,统计记录数量。

      //debug时执行了一次昂贵的数据库交互
      logger.debug(faDao.getFaxxList(kssj,jssj).size ());
      //正确的做法,应该复用之前业务逻辑的查询结果,不要再次执行查询
      int count=faDao.getFaxxList(kssj,jssj).size ();
      
      //do sth use count
      //需要先判断日志级别,不然会有性能消耗,因为日志级别只影响日志输出,但是内容都会计算出来,例如日志里有tostring方法,不管日志级别是什么,都会运行,只是不一定显示
      if(logger.isDebug()){
          logger.debug(count);
      }
      

      说明首先,类似代码不应该提交到svn;其次,如果debug中的代码确实需要执行,则可以增加一个if(logger.isDebug)判断,根据调试级别,避免无效执行。

    • 删除数据库中的一条记录,常见有先使用hibernate的get方法,获取一个bean对象,然后在调用hibernate的delete方法进行删除,这样会有两个数据库操作。实际上直接根据主键删除对象即可,不用先把对象查出来。

    • 数据库查询时,sql中where条件左侧尽量不要使用函数(包括日期函数),以避免降低查询效率。

      Select * from tab where d_larq+3=?;//将不会使用索引
      Select * from tab where trunc(d_larq)=?;//将不会使用索引
      Select * from tab where to_number(C_BH)=?//将不会使用索引
      Select * from tab where c_bh||’01’=?//不会使用索引
      
    • Select *的使用,程序中不建议类似方式,需要明确写出要查询的列,避免列太多。

    • DAO类中,插入数据到数据库,有hibernate的bean,但是仍然使用sql进行插入。应该用hibernate的insert方法,把bean传入即可。

    • 推荐用Integer.valueOf(int)创建Integer对象(其他封装类类似),该方法有可能通过缓存经常请求的值而显著提高空间和时间性能。

    • 不要重复实现apache common包中很多工具类方法。

    • 分页和全部查询可以写一个方法

    • 不应当有空的异常处理块。同时异常信息应该使用日志框架进行记录,不应当调用printStackTrace()方法。该问题在技术备忘录中有要求。

    • 部分try{}catch(..){} 进行了后台日志报错,但是没有给出前台错误提示,这样可能导致用户在已经报错的操作上进行下一步操作,从而引发更严重问题。如果确实不需要提示用户,则可以再注释中进行明确说明。

    • Try代码块不必一味的缩小,相关的业务在一个try中,可确保一个失败而后面的不做。

    • 定时任务不能抛出异常,因为没有程序去管理。定时任务需要自己处理所有的异常信息,并根据异常的情况确定后续的处理流程。可以忽略、重做、发通知等等。

    • 异常的处理最好区分捕获,而不是使用一个try.catch捕获所有的异常

    • List的判空,建议用isEmpty方法,而不要用size()==0

    • 集合类的遍历,建议采用迭代器进行。这是目前比较高效、快捷的。下面列举几种常见的迭代处理代码

      Map<String, String> map = new HashMap<String, String>();
      for (Entry<String, String> entry : map.entrySet()) {
      // 遍历Map
      entry.getKey();
      entry.getValue();
      }
      
      List<String> list = new ArrayList<String>();
      for (String item : list) {
        // 遍历List、Set
      }
      
      Properties props = new Properties();
      for (Entry<Object, Object> entry : props.entrySet()) {
        // 遍历Propties
      }
      
      String[] arrString = new String[0];
      for (String item : arrString) {
        // 遍历数组
      
    • 打开文件后,没有关闭,导致文件占用。
      • 未使用finally处理,导致异常情况下占用资源未释放。

      • 使用了finally处理,多个资源,但是在释放前面资源时发生了异常,导致后面的资源释放失败

    • Dao中使用了getSession,但是没有调用releaseSession,导致数据库链接不释放,应该使用hibernateTemplate提供的方法进行数据库操作,一般情况下不需要getSession。

    • 做文件操作时,直接把文件读入内存,然后进行相应的业务操作,当文件较大,或者线程较多时,会造成内存溢出,导致服务器宕机

      • 压缩程序,接受文件参数,用byte[]数组进行操作,容易造成内存溢出。

      • 应用程序提供文件下载,如果文件较大,线程较多时也会造成内存溢出。

    • SimpleDateFormat有线程安全问题,使用的时候注意线程安全问题,尽量不要使用全局的SimpleDateFormat对象

    • 单例对象的实现,代码中要进行同步的处理,否则有可能创建多个对象。同时对于单例对象的状态、全局属性的修改方法,也要增加synchronized关键字,避免线程安全问题

    • 异常处理中,捕获异常后,没有使用日志框架记录日志的

      日志

    • 记录日志时应该避免出现NullPointException。

    • 每个方法起始应该打印入参数信息,对于对象类型可以转成Json字符串,对于不多的参数用占位符方式输出。

    • 记录trace/debug/info 级别的日志时应使用{}占位符,避免字符串连接减少String对象(不可变)带来的内存开销。

    • 日志内容应该易读、清晰、可描述。要给出当前操作做了什么, 使用的什么数据。

    • 不要在日志中记录密码和个人隐私信息。

    • 记录日志的时候,不要查询数据库。

    • 在for循环中输出日志要谨慎,避免输出大量无用日志。

    • 对于ERROR级别或者WARN级别的日志需要打印异常时相关的参数信息。

    • 应该避免记录日志后有抛出异常,保证日志只记录一次。

    • 代码中不应该出现System print(包括System.out.println和System.error.println)语句

    • 出现异常时应该输出Exceptions的全部Throwable信息,因为logger.error(msg)和logger.error(msg,e.getMessage())这样的日志输出方法会丢失掉最重要的StackTrace信息

      SQL

    • 在循环中(for、wihle),存在查询或更新数据库的脚本,将导致产生大量SQL的问题

    • 在循环中(for、wihle),存在查询或更新数据库的脚本,且没有对垃圾数据进行处理,导致无限循环或一个跨度较大的循环,将导致产生大量SQL的问题

    • 在一次业务处理中,反复从数据库装载同一对象,将导致产生重复大量SQL的问题。

    • SQL脚本操作一批数据,是通过in来实现的,没有预估到in的个数量,导致拼接的SQL很长

    • SQL查询中,不能使用select * 进行查询

    • SQL查询时,条件语句中带or的话,很容易造成全表扫描。最好不要出现这样的sql,可以使用in、union、uion all 代替



    查看原文:http://yuyy.info/uncategorized/%e7%bc%96%e7%a0%81%e8%a7%84%e8%8c%83/
  • 相关阅读:
    解决tmux在PuTTY下工作异常的问题
    使用 Tmux 强化终端功能
    Redis的五种数据结构
    Kubernetes(k8s) docker集群搭建
    C# 正则表达式大全
    C#异步编程(async and await)及异步方法同步调用
    ASP.NET MVC同时支持web与webapi模式
    ActiveX IE保护模式下的低权限操作路径及Windows操作系统特殊路径
    C#文件夹权限操作工具类
    C#创建文件夹并设置权限
  • 原文地址:https://www.cnblogs.com/yuyy114/p/12891376.html
Copyright © 2011-2022 走看看