i++ 引发的惨案

栏目: C++ · 发布时间: 6年前

内容简介:最近在做一个项目,该项目原来是由C++编写的,现在需要翻译成Java,在翻译过程中,同事没有理解清楚具体需求,在开发中进行了直译,直到生产上出现故障了(测试居然没测出来?)一起研究才发现...先看一下C++代码的样子然后看一下同事翻译的第一版的样子

最近在做一个项目,该项目原来是由C++编写的,现在需要翻译成Java,在翻译过程中,同事没有理解清楚具体需求,在开发中进行了直译,直到生产上出现故障了(测试居然没测出来?)一起研究才发现...

需求

先看一下C++代码的样子

//vector<CorBillGroup>& vCorBillGroups 
	while(rs->next()){
		if(load(rs,bill)){
			//判断分组
			corId = pm->getCorpId(bill.getPartyRoleId(),bill.getBillingCycleId());
			if (corId < 0)
				throw BusinessLogicException("找不到银行划扣分组ID", corId);
			int i=0;
			for ( i=0;i<vCorBillGroups.size();i++) {
				 if(vCorBillGroups[i].getCorperationId() == corId){
					 vCorBillGroups[i].add(bill);
					 break;
				 }
			}
			if(i == vCorBillGroups.size()) {
				CorBillGroup corBillGroup;
				corBillGroup.setCorperationId(corId);
				corBillGroup.add(bill);
				vCorBillGroups.push_back(corBillGroup);
			}
		}
	}
复制代码

然后看一下同事翻译的第一版的样子

for (VirtualBillVO vo : bills) {
            long partyRoleId = vo.getPartyRoleId();
            Partner partner = getPartnerManager().getPartner(Integer.parseInt(partyRoleId + ""));
            corId = partner.getCorpId();

            if (corId < 0) {
                throw new BusinessLogicException("找不到银行划扣分组ID", corId);
            }
            int i = 0;
            for (CorBillGroupVO corVo : vCorBillGroups) {
                i++;
                if (corVo.getM_iCorperationId() == corId) {
                    corVo.add(vo);
                    break;
                }
            }
            if (i == vCorBillGroups.size()) {
                CorBillGroupVO corBillGroup = new CorBillGroupVO();
                corBillGroup.setM_iCorperationId(corId);
                corBillGroup.add(vo);
                vCorBillGroups.add(corBillGroup);
            }
        }
复制代码

分析

先不考虑这里具体是干啥的,单纯从代码结构的角度来看,似乎代码是没啥问题的。但是程序可不是看代码结构的! 由于C++代码有具体业务含义,简单介绍一下这段代码的背景:给一组账单(bills),按照运营商(corId)进行分组后返回。这么简单的需求,也不知道C++代码为啥写的这么复杂,这也导致翻译这段代码的同事犯了糊涂。

  • 具体看C++: 循环账单列表,取账单的corId,i=0.循环分组vCorBillGroups,若分组里有该corId就将该账单添加到vCorBillGroups的第i个元素中,并跳出循环,判断i 和vCorBillGroups长度是否相等,若在前面循环中有break,i是不可能与vCorBillGroups的长度相等的(循环vCorBillGroups.size()次,每次i++,则当循环正常结束后,i肯定与vCorBillGroups.size()相等,若有break,则i肯定小于i肯定与vCorBillGroups.size()了);若前面循环中没有break,说明该corId不在已经存在的组中,则添加到vCorBillGroups中。
  • 再看同事翻译的Java:同样循环账单列表,但是采用了foreach的写法遍历,break条件满足之前就i++,那么在无break的时候是正常的,在有break的情况下就不一样了,例如vCorBillGroups.size() = 1 时,遍历一次vCorBillGroups,此时就算有break,i = 1,i ==vCorBillGroups.size();又会重新添加一次分组,那么就与C++代码的含义不一样了。
  • 区别在哪里呢,仔细对比一下就会发现,两处代码的区别就在i++的使用上,for(;;i++)中,若for循环中有break,是不会进行++操作的,同事翻译时为了图方便,随意使用foreach,并将i++置于break条件之前,很明显无法起到控制作用了!

解决

最简单的解决方式就是如上述分析一样,将i++放在break条件之后即可,但是分组代码真的要写这么晦涩吗?见仁见智了...

总结

很少有人真的去注意i++和++i的区别,我老大在看到这段代码的时候也犹豫了一下,后来才恍然大悟怀疑这个i++在break之后是否有执行,测试了一下才确定自己的想法。平时这种代码可能都是不会有问题的,但是一旦触发了某种边界条件,就不一定是你想象的样子了。所以在写代码之前,还是要明确自己要实现的功能是什么,如果同事最开始翻译代码的时候明确知道这是一段分组代码,我相信他绝对不会这样去写的!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

编程匠艺

编程匠艺

(美)古德利弗(Goodliffe, P.)著 / 韩江,陈玉译 / 电子工业出版社 / 2008-9 / 79.00元

如果你可以编写出合格的代码,但是想更进一步、创作出组织良好而且易于理解的代码,并希望成为一名真正的编程专家或提高现有的职业技能,那么《编程匠艺——编写卓越的代码》都会为你给出答案。本书的内容遍及编程的各个要素,如代码风格、变量命名、错误处理和安全性等。此外,本书还对一些更广泛的编程问题进行了探讨,如有效的团队合作、开发过程和文档编写,等等。本书各章的末尾均提供一些思考问题,这些问题回顾了各章中的一......一起来看看 《编程匠艺》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换