`

code review --没有完美的代码(一)

阅读更多

 

我们不但要每天写代码,更应该时时停下来去看看自己的代码:下面是最近项目中code review 发现的一些问题;好的code review 不仅可以减少bug,更加是一个互相学习的过程:

 

 

一、代码背景:很多时候都会碰到数据类型的转换,特别是string 和number之间的转换,这个时候处理的不好,碰上复杂的业务场景,在用户行为不可控的时候,甚至遭到恶意访问的时候,很容易抛出大量异常,降低应用的吐出;

 

 

 if (NumberUtils.isNumber(product.getProductGroupId())) {
          Integer productGroupId = Integer.valueOf(productSearch.getProductGroupId());
          ProductGroupDTO productGroupDTO =productService.findProductGroupDTOByGroupId(productGroupId);
   }
 

这段代码有两个问题:

 

  1、使用了 org.apache.commons.lang.NumberUtils:

很多时间我们在引入类的时候,不会特别关心到底是用的哪一个jar包里面的;对于eclipse等工具的警告和建议也不会去在意;事实上我们应该写一段干净的代码,而不是暂时没有错误的代码;这里应该用 org.apache.commons.lang.math.NumberUtils

 

  2、Integer.valueOf()这个函数当转换失败的时候会跑出NumberFormatException;对于这里并不需要取记录这种错误数据的场景,可以很好的避免这个问题:

修改后如下:

 

 if (StringUtils.isNotBlank(product.getProductGroupId())) {

        Integer authProductGroupId = NumberUtils.toInt(product.getproductGroupId(), -1);
        ProductGroupDTO productGroupDTO =productService.findProductGroupDTOByGroupId(productGroupId);
      }
  

二、代码背景:很多时候我们都需要做一些参数合法性的判断,但是代码写的欢了容易忽略判断的顺序有时候也是很重要的,见下面代码:

 

 

 

 if (companyId <= 0 || companyId == null) {
            logger.error("companyId:" + (companyId == null ? "is null" : companyId.toString())    + ",please check company id.");
           return true;
  }
 

 

 使用foundbug 很容易发现问题:nullpointer early

 

 修改后:

 

 

if ( companyId == null || companyId <= 0 ) {
            logger.error("companyId:" + (companyId == null ? "is null" : companyId.toString())    + ",please check company id.");
           return true;
  }
 

 

三、代码背景:同样是参数合法性的判断,这次的错误就更加隐蔽了:

 

 

  if (map == null && map.size() == 0) {}
 

 

修改后的:

 

 

 if (map == null || map.size() == 0) {}
 

 

 四、 代码背景:很多时候会在一个方法里面去构建一个对象,首先是满足一定的条件,构建对象,设置部分属性,满足另外一个部分条件,在设置另外一部分属性,如果都不满足,返回null;看下面代码:

 

 

public ReportView  buildReportView  (){
   ReportView  reportView  = null;
   if (isHaveReportOne()) {   
            reportView = buildReportOneView(ReportDTOOne);
   }
   if ((isHaveReportTwo()) {
            setReportTwoDTO(reportView , ReportDTOTwo);
            reportView.setOther();
}
    
 private  void  setReportTwoDTO(ReportView reportView , ReportTwoDTO reportTwoDTO){

     if(reportView = null)
     {
         reportView   = new  reportView()
     }
 }

 

  这个问题的关键其实就是:传值还是传引用,假设 isHaveReportOne() ==false;在第二个函数中我们自以为new 了新的对象;并且设置了其他的属性;但是在reportView.setOther()确任然跑出NullPointerException,

 

 

public ReportView  buildReportView  (){
   ReportView  reportView  = null;
   if (isHaveReportOne()) {   
            reportView = buildReportOneView(ReportDTOOne);
   }
   if ((isHaveReportTwo()) {
            reportView =    setReportTwoDTO(reportView , ReportDTOTwo);
            reportView.setOther();
}

 

 

 

private  ReportView  setReportTwoDTO(ReportView reportView , ReportTwoDTO reportTwoDTO){

     if(reportView = null)
     {
         reportView   = new  reportView()
     }
     return reportView   ;
 }

 

 

五、在使用ibatis的时候,通常xml,DAO,DO都是自动生成的,这个时候update会有两个方法,一种是全部更新,另外一个只是更新不为null的值。这个时候使用全部更新要特别注意,如果是不允许用户删除某个字段的修改,最好使用第二种更新。

 

 

六、代码背景:List<DataDto> reports 保存了从DB取出的数据,但是由于涉及到机密,需要将一部分值替换为一个常数;

 

 

public void filterHideItem(List<DataDto> reports) {

        if (reports == null || reports.isEmpty()) {

            return;

        }

        List<DataItemPropertiesDO> hideReportsOne = listAllHideReportsOne();

        List<DataItemPropertiesDO> hideReportsTwo = listAllHideReportsTwo();

        Set<Integer> hideSet = new HashSet<Integer>(( hideReportsOne .size() + hideReportsTwo.size()) * 4 / 3);

        ListTOSet(hideSet, hideReportsOne );

        ListTOSet(hideSet, hideReportsTwo );

       // 循环比较如果是在需要被屏蔽的集合里面,则替换为一个常数

        for (DataDto dataDto: reports) {

            filterReport(hideSet, dataDto);

        }

    }

    private void filterReport(Set<Integer> hideReports, DataDto  report) {

        if (report == null) {

            return;

        }
    //需要过滤的报告数据
        List<NormalDataDto> list = report.getNormalReports();

        for (NormalDataDto normalDto : list) {

            if (hideReports.contains(normalDto.getId())) {

                normalDto.getSummaryKeyValueMap().put(Constants.KEY_ONE,

                                                      Constants.VALUE);

                normalDto.getSummaryKeyValueMap().put(Constants.KEY_TWO,

                                                      Constants.VALUE);

            }

        }

    }

    // 获取 第一种类型需要被屏蔽的数据

    private List<DataItemPropertiesDO> listAllHideReportsOne() {

        DataItemPropertiesDO param = new DataItemPropertiesDO();

        param.setKey(Constants.KEY_ONE);

        param.setName(Constants.ATTRIBUTE_HIDE);

        param.setValue(Constants.ATTRIBUTE_HIDE_TRUE_VALUE);

        List<DataItemPropertiesDO> list = service.listItemPropertiesByParam(param);

        if (list == null || list.isEmpty()) {

            return null;

        }

        return list;

    }

   //获取 另外一种需要被屏蔽的数据

    private List<DataItemPropertiesDO> listAllHideReportsTwo() {

        
        DataItemPropertiesDO param = new DataItemPropertiesDO();

        param.setKey(Constants.KEY_ONE);

        param.setName(Constants.ATTRIBUTE_HIDE);

        param.setValue(Constants.ATTRIBUTE_HIDE_TRUE_VALUE);

        List<DataItemPropertiesDO> list = service.listItemPropertiesByParam(param);

        if (list == null || list.isEmpty()) {

            return null;

        }

        return list;
    }

    // 将List 转换为 set

    private void ListTOSet(Set<Integer> hideSet, List<DataItemPropertiesDO> list) {

        for (DataItemPropertiesDO prop : list) {

            hideSet.add(prop.getReportId());

        }

    }
 

 

 

第一个问题很容易发现:nullpointer 是javaer最常见也最防不胜防的问题;很多公司更是作为一个约定不允许任何方法返回null;问题就出现在

 

 

 Set<Integer> hideSet = new HashSet<Integer>((hideReportsOne.size() + hideReportsTwo.size()) * 4 / 3);
 

 

   这里的 hideReportsOne ,hideReportsTwo 可能为null; 一方面提供服务的一方 要尽可能的不返回 null 可以考虑  Collections.emptyList() 代替 null;另一方面  永远不能依赖别人的正确性,

 

 第二个问题也不难,  可以发现 listAllHideReportsOne 和 listAllHideReportsTwo 是非常类似,只是查询的key不相同,如果将来在新增一个需要过滤的数据,现在的方式必然要再新增一个类似的方法,可见可扩展性非常不好:

 

一种方案:

 

 

     private List<String>               hideItemKeys;

      public ItemHideFilterProcessor() {

        hideItemKeys = new ArrayList<String>(2);

        hideItemKeys.add(Constants.KEY_ONE);

        hideItemKeys.add(Constants.KEY_TWO);

    }
 
    public void filterHideItem(List<DataDto> reports) {

        if (reports == null || reports.isEmpty()) {

            return;

        }

        List<ItemHideReport> itemHideReportList = buildItemHideReports();

        if (itemHideReportList.isEmpty()) {

            return;

        }

        for (DataDto dataDto : reports) {

            filterReport(itemHideReportList, dataDto );

        }

    }

    private void filterReport(List<ItemHideReport> hideReportSetList, DataDto report) {

        if (report == null) {

            return;

        }

        List<NormalDataDto> list = report.getNormalReports();

        for (NormalDataDto normalDto : list) {

            for (ItemHideReport hideReport : hideReportSetList) {

                if (hideReport.isHide(normalDto.getId())) {

                    normalDto.getSummaryKeyValueMap().put(hideReport.getItemKey(),

                                                          CertifiedReportConstants.CONFIDENTIAL);

                }

            }

        }

    }

    private List<ItemHideReport> buildItemHideReports() {

        List<ItemHideReport> list = new ArrayList<ItemHideReport>(hideItemKeys.size());

        for (String hideKey : hideItemKeys) {

            Set<Integer> reportSet = listAllItemHideReportsByKey(hideKey);

            if (reportSet != null) {

                list.add(new ItemHideReport(hideKey, reportSet));

            }

        }

        return list;

    }

    private Set<Integer> listAllItemHideReportsByKey(String key) {

        DataItemPropertiesDO param = new DataItemPropertiesDO();

        param.setKey(key);

        param.setName(Constants.ATTRIBUTE_HIDE);

        param.setValue(Constants.ATTRIBUTE_HIDE_TRUE_VALUE);

        List<DataItemPropertiesDO> list = itemService.listItemPropertiesByParam(param);

        if (list == null || list.isEmpty()) {

            return null;

        }

        Set<Integer> set = new HashSet<Integer>(list.size() * 4 / 3);

        for (DataItemPropertiesDO prop : list) {

            set.add(prop.getReportId());

        }

        return set;

    }

    class ItemHideReport {
        String       itemKey;
        Set<Integer> hideReports;

        public ItemHideReport(String itemKey, Set<Integer> hideReports) {

            this.itemKey = itemKey;

            this.hideReports = hideReports;

        }

        public String getItemKey() {

            return itemKey;

        }

        public boolean isHide(Integer reportId) {

            return hideReports.contains(reportId);

        }

    }

}
0
0
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    IDEA代码检视插件Code Review Helper(支持团队协同)

    在实际使用中,下载的压缩包文件"IntellijIDEA-CodeReview-Plugin-master"包含了插件的源代码,开发者可以对其进行定制或扩展以满足特定团队的需求。安装插件通常包括以下几个步骤: 1. 解压下载的压缩包。 2. 打开...

    ivotical-codereview-gitlab:Gitlab的代码审查集成帮助器

    `pivotical-codereview-gitlab` 是一款专门为 Gitlab 设计的代码审查集成工具,它旨在简化和优化代码审查流程,提升团队的开发效率和代码质量。 Gitlab 是一个开源的版本控制系统,它提供了全面的 DevOps 平台,...

    代码审查CodeReview的最佳实践

    我一直认为CodeReview(代码审查)是软件开发中的... 然而对于我观察到的大部分软件开发团队来说,认真做CodeReview的很少,有的流于形式,有的可能根本就没有CodeReview的环节,代码质量只依赖于事后的测试。也有些

    静态测试方法之代码审查(CodeReview)的清单

    静态测试方法之代码审查(CodeReview)的清单。代码审查可以帮助提高代码质量,避免由于代码习惯而造成的bug。下面列出的这些要点因该可以作为大部分代码审查的指导,如果是Java应用的话,这些建议应该被视作最佳实践...

    Source Insight CodeReview宏,增加使用说明

    **Source Insight CodeReview宏**是专门针对Source Insight这款强大的源代码查看和编辑工具设计的一套扩展功能,主要用于代码评审和统计。Source Insight以其强大的代码导航、语法高亮和实时分析能力,深受程序员...

    PHP-Code-review.rar_PHP codereview_php code review_php代码review

    代码审核,是对应用程序源代码进行系统性检查的工作。它的目的是为了找到并且修复应 用程序在开发阶段存在的一些漏洞或者程序逻辑错误,避免程序漏洞被非法利用给企业带来不必 要的风险。

    基于Gitlab的代码审查流程(Code-Review)方案

    代码审查是软件开发中一个至关重要的环节,它涉及对源代码的详细检查,以确保代码符合项目的编码标准和质量要求。代码审查可以借助不同的工具和平台进行,包括GitHub的Pull-Request机制和GitLab的Merge-Request机制...

    code review代码检测原理

    **代码审查(Code Review)是软件开发过程中的一个重要环节,旨在提高代码质量,发现潜在的错误,提升团队协作效率,并确保代码遵循最佳实践和项目规范。本文将深入探讨代码审查的原理、步骤以及如何有效地执行代码...

    CodeReview工具

    Code Review是软件开发过程中的一个重要环节,它有助于提高代码质量,发现潜在的错误,以及确保团队成员间的代码风格一致。本文将详细介绍两款Eclipse插件——Jupiter和Reviewclipse,它们是进行Code Review的有力...

    CodeReview工具Jupiter

    Code Review的作用和意义已在很多技术团队内达成共识,可是很多时候并未被有效执行,甚至被认为是一项费时费力的工作。借助一些工具可以更容易,更有效率地来进行Code Review,本文介绍的Jupiter即是其中之一。  ...

    code-review-emoji-guide:一个表情符号图例,可帮助传达意图并在代码审查注释中添加含义

    `code-review-emoji-guide` 是一个专门为这个目的设计的资源,它提供了一套表情符号图例,帮助开发者在进行代码审查时更有效地传达他们的意见和反馈。下面将详细探讨这个指南及其相关知识点。 1. **代码审查的重要...

    Steven Code Review 代码在线审查

    Steven Code Review 2009.12M1发布包.rar 代码在线审查工具 @date: 2009-12-28 @author: YF @email: yifi@tom.com 功能: 1 方便学员学习教师的代码,无需在本机运行IDE即可以代码加亮的方式查看服务器共享的代码...

    在 GitHub 上玩转开源项目的 Code Review.doc

    在 GitHub 上,Code Review 是一个非常流行的实践,它可以帮助开发者提高代码质量,减少错误和漏洞。 在本文中,我们将探讨如何在 GitHub 上玩转开源项目的 Code Review。首先,我们需要了解 Code Review 的概念和 ...

    ReviewCode-master.rar

    【标题】"ReviewCode-master.rar" 是一个压缩文件,通常包含了一个名为 "ReviewCode-master" 的项目或代码库。在IT行业中,这样的命名通常表示这是一个关于代码审查的项目,可能是为了教学、分享最佳实践或者是一个...

    Source Insight 宏 codeReview.em

    CodeReview工具的作用:1.减少评审人的缺陷记录和汇总时间,方便责任人查找问题出处;2.检视完成后生成检查报告,代码作者点击按钮可以直接找到错误处;3.任务责任人修改完成后,直接修改问题状态,组织者按快捷键...

    Redmine插件Code Review使用介绍

    在Redmine中,Code Review插件是一个重要的扩展,它致力于帮助开发团队进行代码审查,提升代码质量和团队协作效率。本文将详细介绍如何使用Redmine的Code Review插件。 首先,安装Code Review插件是必要的步骤。...

    Pau Code Review-开源

    Pau Code Review 是一款专为开发者设计的轻量级代码审查工具。这款工具的核心理念在于提供一个基础框架,帮助开发者进行代码审查,但不规定具体的审查流程,允许用户根据自己的团队规范和项目需求自定义审查过程。这...

    jupiter--code review工具

    一个很方便的功能是其建立了review问题跟具体源代码的对应关系(通过点击review问题列表中的问题可以跳转到对应的代码段,通过点击代码段上的review问题标记可对应到具体的问题描述),review问题列表支持各种filter...

    Codereview 代码审查工具(国人开发)

    软件介绍: 一、软件特色 功能丰富:实现文件内容、度量、命名、注释、类图、Halstead等审查。 简单易用:无需安装,直接使用,直接删除;... 直观可视:分析结果与源代码在同一界面显示对照,...http://www.codereview.com.cn

    GitHub-code-review-helper:Tampermonkey 脚本,允许通过单击差异标头来打开隐藏 GitHub 差异

    【GitHub-code-review-helper】是一个基于Tampermonkey的用户脚本,专为提升GitHub代码审查体验而设计。Tampermonkey是一款浏览器扩展,它允许用户安装自定义的JavaScript脚本来修改网页内容,以满足个性化需求。在...

Global site tag (gtag.js) - Google Analytics