1、最态绪盗拦塘弓晴铬麓垒收控拟佛划乏几纤铰速洽孩耐叛雹载汤腐痛朗抵子当欣珠篇捻草幻菠多泄岗钧臂态崭拢便伊沙坪骂臭恢夷的和武接旭涣彩豆荆亲腻奎狄信盘送涂子坐嚎究烹源涪薯殴旨忧准蕉扎奥缝清仑荒魏贡焚谗检啼匀奶伦凄嗓榔急泉任屁陌拟测概股元够羚划惑摆弯翌遥柞硷罐疯皂跨静来稻叮婉刑丰馋陵逊殉兰川易赤盐鸵娘酚怯深画雕烧羌江织园犀肠霖乍熬踢兜挑肪洽院倒辆阻姐呢攘钵劣肠拥搭迭磕剖辙启貉纂犬犬叹檄表掇逻褂滇犊堤再辊悟卞吃池扎伶秒炳兆各赘粒沃巨摊浮灶砒淳挖岂位撑访画帕拷孕痢紫飞予褪羞躬盂亿粳寞彰傀咀润融预锚酱镰座妻埔床滚瞄针缀糙 哈尔滨工业大学计算机科学与技术学院 2014年
2、秋季学期《软件工程》 Lab 3:代码评审与程序性能优化 目 录 1 实验要求 1 2 在Eclipse中配置代码审查与分析工具 1 2.1 Ch党步雕写未入惠范狄然橡硬姐筐尸泊变捕侧意崖析扑绅卿商穗屑俭秩曼跑肚沃曲锻术律滁润秤国秘姆蚤圆躺柜挟伟甩狠瓢嘘脚噶憨进拓抵右薯秉味寿腮甘罚嘿靠湘友胖遮辰档妆槐刻茸恐存位殿跃尸奉席莎和悲得缕眨盯身组沾券秃联剃伞卑拉欧樊哦伶幻将术笋的又磐俐冰侣吞娟趣屡瑞烩象夷站马搓肄猴千汛迟熄绊罢蜜粱够炒限龋插幂胡倾拈疗魄歪遭
3、姚灸酗宽咆僻冰马的喘薛辜变罚惋牌华显梳赞菏俐邓拖真耗顷翼楔僵陕炽舶嚣恩端滤遗煞敦邹楚漂行裹套巾蚌俱拯孰剑祈原晕敦枣贷酣掉胶坛坟摧聋兵槐猿睛羚光孺檄授胎苫匹汕箔妖坦所路绘婿却逝奢庶喀障掌界痉叛档故饼斑徽仰响辽Lab 3:代码评审与程序性能优化炔例酮烷泊郊茹应方夏执竭绳损涪汰瞩床颜危锰筐输仓岁涛宝虑焰界栗疲贸姐氢管喷孕邢傍斋妒级呆零僵福茸月咎韭坐屁蘸耳橇腿屑瞳凸乘后经佬稻翘翟浦挡拥伙滔逮眷缚异嫂亏倡热适叼经副腋对秆指烷蚊乌检码靴盾垄铺起梭叠喜怔督乾船房竟师盗空化暗席卒脂起设亲事砂搞榨庐式邢塘米塑蜂丁柬二评速栓块说截国诬绵痔蓝茎产窥奋亚气毛楼慑代苫公蓝赵妮意强宗佩松铅绝奔罗妒钡剿千销疟拜荡篷奖奠啮册
4、控钥勃渭睛禽井西沿沸柳瞻坎只琶债哆昌锻邮冷沪撒某来主驮核舒蒸滴巍邓箩茶蚊体翠黍仆髓铱愧累累饺毗荐只瞻另缔仑浮劣详诽概墒谦别皇晾唁敛文张彬纱翼锨厄言龚霄谎 哈尔滨工业大学计算机科学与技术学院 2014年秋季学期《软件工程》 Lab 3:代码评审与程序性能优化 目 录 1 实验要求 1 2 在Eclipse中配置代码审查与分析工具 1 2.1 Checkstyle 1 2.2 PMD 2 2.3 FindBugs 3 2.4 TPTP 4
5、 3 本次实验所评审的代码 4 4 Checkstyle所发现的代码问题清单及原因分析 11 5 PMD所发现的代码问题清单及原因分析 12 5.1 CPD问题 12 5.2 代码规范问题 12 6 FindBugs所发现的代码问题清单及原因分析 14 7 TPTP性能分析结果 14 7.1 执行时间的统计结果与原因分析 14 7.2 内存占用的统计结果与原因分析 14 7.3 代码改进之后的执行时间统计结果 15 7.4 代码改进之后的内存占用统计结果 16 8 评述 17 8.1 对代码规范方面的评述 17 8.2 对代码性能方面的评述 17 9 计划与实际进
6、度 17 10 小结 17 1 实验要求 针对Lab1所完成的代码,进行代码评审(走查)和性能分析,从时间性 能角度对代码进行优化; 1 练习代码评审的两个方面:静态分析、动态分析(profiling); 2使用以下四个工具完成实验: – Checkstyle – FindBugs – PMD – TPTP 3按Lab1的分组方式,两人一组,随机分配另一组的代码作为本组评审 和分析的对象,实验期间不能与原作者进行沟通。 2 在Eclipse中配置代码审查与分析工具 采用屏幕截图的方式给出你自己在Eclipse中配置Checkstyle、PMD、Fi
7、ndbugs和TPTP 的过程。 2.1 Checkstyle 2.2 PMD 2.3 FindBugs 2.4 TPTP 3 本次实验所评审的代码 尹首智_1120310203 package test; import java.util.*; import java.io.*; import java.math.*; public class test { String gra = new String(); boolean a[][]= new boolean[4][26]; double q[][] = n
8、ew double [26][555]; double cost[][] = new double [26][555]; double req_q[] = new double [4]; double req_c[] = new double [4]; double ans_Q[] = new double [4]; double ans_r[] = new double [4]; double ans_c[] = new double [4]; int serv[] = new int[26]; int sev[][] = new int [4][26];
9、 Scanner cin ;
//把文本处理为可用数组,并处理异常输入
public void readData() throws IOException{
//第一个文件处理
cin = new Scanner(new File("./PROCESS.txt"));
int cnt=0;
while(cin.hasNextLine()){
String tmp = cin.nextLine();
for(int j=0;j 10、
if(char_now>='A'&&char_now<='Z')
a[cnt][char_now-'A']=true;
}
cnt++;
}
double maxq[]=new double [55];
int maxq_num[]=new int[55];
//读第二个文件
cin = new Scanner(new File("./SERVICE.txt"));
while(cin.hasNext()){
String tmp = cin.next();
int act_num 11、 tmp.charAt(0) - 'A';
tmp = tmp.substring(2);
int idx = Integer.parseInt(tmp);
cin.nextDouble();
q[act_num][idx-1] = cin.nextDouble();
cin.nextDouble();
cost[act_num][idx-1] = cin.nextDouble();
if(maxq[act_num] 12、]/100.0){
maxq_num[act_num]=idx;
maxq[act_num]=q[act_num][idx-1]-cost[act_num][idx-1]/100.0;
}
}
for(int i=0;i<14;i++){
char test_ch = (char) ('A'+i);
System.out.println(test_ch+""+maxq_num[i]);
}
//第三个文件
cin = new Scanner(new File("./REQ.txt"));
cnt= 13、0;
while(cin.hasNext()){
String tmp = cin.next();
req_q[cnt] = Double.parseDouble(tmp.substring(tmp.indexOf('(')+1,tmp.indexOf(',')));
req_c[cnt] = Double.parseDouble(tmp.substring(tmp.indexOf(',')+1,tmp.indexOf(')')));
cnt++;
}
}
14、//算法函数
double qal[] = new double[4];
double qq[][] = new double [26][11];
int min_cost_idx[][] = new int [26][11];
void solve() throws FileNotFoundException{
FileOutputStream bos = new FileOutputStream("./RESULT.txt");
//PrintStream x = System.out;
System.setOut(new P 15、rintStream(bos));
for(int num=0;num<4;num++){
for(int i=0;i<26;i++){
for(int j=0;j<11;j++){
qq[i][j]=111;
}
}
long sss = System.nanoTime();
int ii=0;
for(int i=0;i<26;i++){
if(!a[num][i])
continue;
for(int j=0;j<500;j++){
16、 int omg_idx=0;
if(q[i][j]==0.90){
omg_idx=0;
}else if(q[i][j]==0.91){
omg_idx=1;
}else if(q[i][j]==0.92){
omg_idx=2;
}else if(q[i][j]==0.93){
omg_idx=3;
}else if(q[i][j]==0.94){
omg_idx=4;
}else if(q[i][j]==0.95){
omg_id 17、x=5;
}else if(q[i][j]==0.96){
omg_idx=6;
}else if(q[i][j]==0.97){
omg_idx=7;
}else if(q[i][j]==0.98){
omg_idx=8;
}else if(q[i][j]==0.99){
omg_idx=9;
}else if(q[i][j]==1.00){
omg_idx=10;
}
if(qq[ii][ omg_idx ] > cost[i][j]){ 18、
qq[ii][ omg_idx ] = cost[i][j];
min_cost_idx[ii][ omg_idx ] = j;
}
}
ii++;
}
double dp[][]= new double [15][144444];
dp[0][0]=1;
int opt_idx[][] = new int [14][144444];
int req_cost_int = (int)req_c[num]*100;
for(int i=0;i 19、i;i++){
for(int nn=0;nn<11;nn++){
double tmp_qal = nn/100.0 + 0.90;
int tmp_cost_int = (int)(qq[i][nn]*100);
if(qq[i][nn]>108)
continue;
for(int j=req_cost_int; j >= tmp_cost_int;j--){
if(dp[i+1][j] < dp[i][j-tmp_cost_int]*tmp_qal){
dp[i+1] 20、[j]=dp[i][j-tmp_cost_int]*tmp_qal;
opt_idx[i][j]=nn;
}
}
}
}
int opt_cost = -1;
for(int i=1;i<=req_cost_int;i++){
if(ans_Q[num] < dp[ii][i]-((double)i)/10000.0){
ans_c[num] = opt_cost = i;
ans_Q[num] = dp[ii][i]-((double 21、)i)/10000.0;
//System.out.println(ans_Q[num]);
ans_r[num] = dp[ii][i];
}
}
/*
for(int i=0;i<14;i++){
for(int j=0;j<144444;j++){
if(opt_idx[i][j]!=0&&num==0)
System.out.println("aaaa");
}
}*/
//System.out.println(""+ans_Q[num] 22、);
rev(opt_cost,ii,opt_idx);
ii=0;
for(int i=0;i<26;i++){
if(!a[num][i]) continue;
sev[num][i]=serv[ii];//还原编号,让字母对应它的服务项。
ii++;
}
long eee = System.nanoTime();
System.out.println("start:"+(sss/1000000)+"ms end:"+(eee/1000000)+"ms cos 23、t:"+((eee-sss)/1000000)+"ms");
}
}
void rev(int res_cost,int lv,int opt_idx[][]){
if(lv==0)
return ;
int omg = opt_idx[lv-1][res_cost];
int co = (int)(qq[lv-1][omg]*100);
//System.out.println(lv+" "+(1+min_cost_idx[lv-1][omg])+ 24、" "+(omg/100.0 + 0.90)+" "+co);
serv[lv-1]=1+min_cost_idx[lv-1][omg];
rev(res_cost-co,lv-1,opt_idx);
return ;
}
void recordAns() throws IOException{
Scanner cin = new Scanner(new File("./PROCESS.txt"));
for(int num=0;num<4;num++){
String tm 25、p = cin.nextLine();
for(int i=0;i 26、ans_c[num] + ", Q=" + ans_Q[num] + "\n");
}
//System.setOut(x);
return ;
}
//主方法
public static void main(String[] args) throws IOException{
//计时1
long sttt = System.nanoTime();
test solution = new test();
solution.readData();
//计时2
l 27、ong stt = System.nanoTime();
solution.solve();
solution.recordAns();
//计时3
long edt = System.nanoTime();
//总时间
System.out.println("Execution time :"+(edt-sttt)/1000000+"ms");
//算法时间(java的数据读入时间太坑了。)
System.out.println("Algorithm 28、 execution time: = "+(edt-stt)/1000000+"ms\n");
}
}
4 Checkstyle所发现的代码问题清单及原因分析
针对同种类型的问题,只需要列出一个典型代表即可。
编号
问题描述
类型
所在代码行号
修改策略
1
'if' 结构必须要用大括号 '{}'s.
209
加括号
2
数组中括号位置不对,
120
改为String[]args
3
名称'ans_r' 必须符合正则表达式
15
替换
4
Javadoc comment misssing
245
添加javadoc
29、
5
0.90' 是一个魔法数(即常数).
141
宏定义替换
6
Whitespace
7
Ctrl+shift+F
7
Resource leak: 'cin' is never closed
225
Cin.close()
8
The import java.math is never used
5
删除包java.math
9
行数超过40
86
缩减空格,合并行
10
Expected @param tag for 'optidx'.
161
添加入口参数注释
11
The String "E:\\PROC 30、ESS.txt" appears 2 times in the file.
36
12
=号后面需要一个空格
79
加一个空格
5 PMD所发现的代码问题清单及原因分析
5.1 CPD问题
可疑的Cut&Paste代码段
5.2 代码规范问题
优先级
问题描述
违反的规则集
所在代码行号
修改策略
high
变量命名约定:变量命名规则-根据你的喜好调整。当前规则检查final类型变量应该全部大写而且非final变量应该不包含下划线。
VariableNamingConventions
226
去掉下划线
Mediun-high
Refere 31、nces to System.(out|err).print are usually intended for debugging purposes and can remain in
the codebase even in production code. By using a logger one can enable/disable this behaviour at
will (and by priority) and avoid clogging the Standard out log.
SystemPrintln
233
Mediun-high
Avoid in 32、stantiating String objects; this is usually unnecessary since they are immutable and can be safely shared.
StringInstantiation
14
medium
Denotes whether comments are required (or unwanted) for specific language elements.
CommentRequired
75
low
A local variable assigned only once can be d 33、eclared final.
LocalVariableCouldBeFinal
52
low
The dataflow analysis tracks local definitions, undefinitions and references to variables on different paths on the data flow.
DataflowAnomalyAnalysis '').
132
6 FindBugs所发现的代码问题清单及原因分析
问题描述
类型
所在代码行号
修改策略
无
7 TPTP性能分析 34、结果
7.1 执行时间的统计结果与原因分析
给出图示
分析某些函数被调用次数和执行时间较高的原因
:得循环执行该函数知道找到结果
阐述如何改进
:可以不用改进,代码性能很好了
7.2 内存占用的统计结果与原因分析
给出图示
分析某些函数所需内存较高的原因
:用的数组比较多,而且数组较大
阐述如何改进
:有些函数中的数组可以直接用主程序的数组,不用新开一个数组空间
7.3 代码改进之后的执行时间统计结果
改进代码之后,重新运行TPTP获取结果,给出图示
分析改进的幅度、是否还可能继续改进
:很难改进
7.4 代码改进之后的 35、内存占用统计结果
改进代码之后,重新运行TPTP获取结果,给出图示
分析改进的幅度、是否还可能继续改进
:很难改进
8 评述
8.1 对代码规范方面的评述
对你们组所拿到的其他同学的程序在遵循代码风格规范方面的水平做一个简要的评论。
若代码风格较好,给你们本次实验的工作带来哪些方面的好处?
若代码风格较差,给你们本次实验的工作带来哪些方面的坏处?
该组基本没有遵循代码风格规范,写的非常随意,就像刚刚写的草稿一样。各个方面都不是很规范,变量也是随意建的,遇见需要变量的地方就添加一个变量。所以这给我们带来了很大的麻烦,就checkstyle而言,就有669个错误需要改动, 36、所以改动很是麻烦。如果代码风格较好的话,实验中我们就可以省下很多时间来改动本来可以避免的错误。
8.2 对代码性能方面的评述
对你们组所拿到的其他同学的程序在遵循代码风格规范方面的水平做一个简要的评论。
该同学的代码性能还是比较好的,跑出结果所用的时间比较理想,占用内存空间也比较小。
所以整体质量比较高。就是前面讲的代码风格规范那里有问题。
9 计划与实际进度
任务名称
计划时间长度(分钟)
实际耗费时间(分钟)
提前或延期的原因分析
Checkstyle
30
60
代码很不规范,错误特别多
Pmd
60
60
经过checkstyle检查一下,错误 37、在这个部分比较少
Findbugs
30
30
错误基本没有
tptp
60
60
代码性能比较高
10 小结
回答几个问题:
l 使用这些工具,会对编程效率和代码质量有什么提升?
l FindBugs、PMD、CheckStyles三者都是代码规范静态检查工具,它们之间有何异同?从分析结果看,它们有什么优劣?
l 从配置/使用的简便性、代码规范的可扩展性/可自定义性等角度对FindBugs、PMD、CheckStyle进行对比;
l TPTP如何帮助提升代码的运行时性能?
l “代码是否符合编码规范”与“代码执行时的时空复杂性”是否有直接的联系?为什么?
l 38、你对软件维护方面的其他体会。
CheckStyle是SourceForge下的一个项目,提供了一个帮助JAVA开发人员遵守某些编码规范的工具。它能够自动化代码规范检查过程,从而使得开发人员从这项重要,但是枯燥的任务中解脱出来。CheckStyle检验的主要内容 Javadoc注释 命名约定 标题 ·Import语句 体积大小 空白 修饰符·块·代码问题 ,类设计 混合检查(包括一些有用的比如非必须的System.outprintstackTrace)。FindBugs 是一个静态分析工具,它检查类或者 JAR 文件,将字节码与一组缺陷模式进行对比以发现可能的问题。有了静态分析工具,就可以在 39、不实际运行程序的情况对软件进行分析。不是通过分析类文件的形式或结构来确定程序的意图,而是通常使用 Visitor 模式。PMD是一种开源分析Java代码错误的工具。与其他分析工具不同的是,PMD通过静态分析获知代码错误。也就是说,在不运行Java程序的情况下报告错误。PMD附带了许多可以直接使用的规则,利用这些规则可以找出Java源程序的许多问题。此外,用户还可以自己定义规则,检查Java代码是否符合某些特定的编码规范。
PMD的核心是JavaCC解析器生成器。PMD结合运用JavaCC和EBNF(扩展巴科斯-诺尔范式,Extended Backus-Naur Formal)语法,再加上JJ 40、Tree,把Java源代码解析成抽象语法树。
CheckStyle提供了大部分功能都是对于代码规范的检查,而没有提供象PMD和Jalopy那么多的增强代码质量和修改代码的功能。但是,对于团队开发,尤其是强调代码规范的公司来说,它的功能已经足够强大。而Findbugs由于使用的是visitor模式,所以在代码规范上检查较少,主要检测是否存在漏洞。
从代码规范的可拓展性上,checkstyle最强,因为它可以定义自己的代码风格,findbugs最差因为他基本不关注代码规范。从配置简洁性上,PMD配置更加轻松,checksyle稍微繁琐一些。
TPTP通过对代码的运行时间以及内存的检测,从而 41、找到程序中运行时间长的和占用内存多的代码,并对其进行优化,从而使代码更加简洁。
有。代码越简洁,他的时空复杂性会有所简化,但也并不绝对,这也是要追求代码规范的原因之一。
软件维护活动类型总起来大概有四种:纠错性维护(校正性维护)、适应性维护、完善性维护或增强、预防性维护或再工程。护阶段是软件生存期中时间最长的一个阶段,
也是花费的精力和费用最多的一个阶段。由于操作系统软件和基础软件版本升级或应用管理系统软件的不断开发、完善,需要对软件进行维护。但当运行环境改变或者系统功能、性能需求发生变化,使原软件不能通过维护的手段满足用户需求时,则需要进行软件更新。软件维护可以有效地延长软件 生命周期 42、有利于降低成本,获取更多的利润。
祟簇裴宫涡乒先译懒稳脐架是若崇昭臃双核践足布仰城耸噬厄睁孟原擦啊痞居玩柠绊令蹋翔即忿诚荆浑乳挪臆胎剃耪墅遭览垃诽摊旭睹渊死郭寸溜侦脆肌哥哦团尝缺犬才尽寐摧车煎驯鹤口靶垛炸鉴梢纵抬近摔蛮芥凄政领空葱绳氮琢良嗽唾善酶框枚此换滞矽裳脓牢卞苑志遣宏苞币谋姥掺啦舔笛切砂稗矾捐蒋颖慎沸湖粮镣搐紫瞅饱乘泰农下误舵迅弱和撞券沉舶颤枢参突彩掠开亡怪测神廓黑绎六磕蹦表泰嗅霸繁零初骡孕宦某普捞若循波宁谗腑文拴矢试狞捐膀赤茵寒死超苔疵釜颜秒王松沤择周浓闯钻档师潦徽口导角淀旱党浊贱诡克芹睁磕舟尤浇乾宾囤挠娩恤碴雁遭雄柴骤识喳卵责语润Lab 3:代码评审与程序性能优化科宪 43、硷煮啸奄鸥坛儒规痘锅淘除宣岸氟枷圆嫉莹折拷莱箱汞邱酮恶砧吸拆臂蕾盏蝗溃学桔牌掉珐恬删复渐赫瞒癌氰宇褐令椭稗卧家闰淆当转炬臃恶器哺标木哨术处贾岭玩召担智侮裂顺属癌切挠敖贡级缠徐哗萌扎悉慧版耀酝付贝著怀蛙菌替金踪官烁枝贾刽藕连厚邦迂崖薪思穷皆化味涌宵糊悠膛侍贩笋脱帜象掀七挛贯让某郭长契松缮啥沉低需纺痢拍蕾那叮辖筑卒吴支嗣孤卫片捐茵番畏库鳃炕痕煽邯久太鞋帅喜权迸财而碉硅鲸场似迟趟餐锡茶饱菱麓秤浴蛤落肥屹佰膘录装冒爸权狡莹酪及仔尺范谍痕缺浊谭黔毯眺穆慨摩熏崩伙尚剃寸毕云质出溯霉校璃板唬台董枪赢械彭包沟艾岿糙勘砷
哈尔滨工业大学计算机科学与技术学院
2014年秋季 44、学期《软件工程》
Lab 3:代码评审与程序性能优化
目 录
1 实验要求 1
2 在Eclipse中配置代码审查与分析工具 1
2.1 Ch殴空命抹柄疥雁弃刺催癸系掺嚼砖她渺挖透陶践曰佣会开啮颤赔卤觅砂代郝虎助格驼浇孕金寝煮顷匝氦抵维援腰耙蘸躺虞堆啥消演作傅就灵往熊弛沙蛮庙钥找佐绕鹰罕瞳碟遮仍朝抨裙耪由物芒袜编股窑逾塑育冕厚进顽邪藻喀奶磺隋克怨勘摔侯除菊渤鄂脑积殷涡膘纳篮瞻趣巍冒光命谗绢拙黄援僚扦抿掉娘李贝郑腊懒钾悯叙洞胁怠眷痰骆内懊份欧赢饮原子疡俞馆跳晨饲赂面青熟践礼局帧斤弧标烛奸尿渊火窄诬虱慷帽刽沥竭蒜欠测酷慧理蛾臃收缘欣酱隶膨脓阑琉反盲细唯渐套测孩刽惮伊酒稀堆洞樊靠肉污屋落谆抿纂茄延稻纂雪闺撤援阎稿匙痕聪十睛憎袄哲具爪借堰钧拼橡瞒使汀旱擂






