|
|
|
|
|
[文章信息] |
|
作者: |
陈雄华 |
时间: |
2005-01-04 |
出处: |
天极网 |
责任编辑: |
方舟 |
|
[文章导读] |
|
代码审查作为JBuilder 2005强大的新特性闪亮登场,直指编码中的软肋 |
|
|
|
|
|
|
|
· |
1元搞定价值千元的数码,注册有大奖 |
· |
CN域名买一送二 |
· |
智能手机的颠峰 |
· |
理光万元水晶疯狂送 |
· |
超清晰免费和MM亲密私语 |
marginwidth="0" marginheight="0" src="http://219.239.88.50/adsunion/get/;pl=pl-20-soft-svbanner;tp=if;sk=0;ck=0;/?" frameborder="0" width="1" scrolling="no" height="1"> |
|
|
· |
Windows XP Pro版与Home版的比较 |
· |
3Ds Max7中简单的新增及改进功能 |
· |
WMP 10实用技巧两则 |
· |
Windows无法删除文件的解决办法 |
· |
歪批IT系列之“伪热门”人才 |
|
|
|
|
|
|
|
|
|
代码审查作为JBuilder 2005强大的新特性闪亮登场,直指编码中的软肋,力争将编码中的错误或隐患扼杀于萌芽态,强力提升开发人员的编码质量。
JBuilder 2005根据Sun的编码规范及软件开发界总结出的一套行之有效的编码习惯,对Java开发中的编码风格、声明风格、Javadoc文档注释、EJB规范、命名风格、潜在错误、编码中的画蛇添足等诸多方面进行代码审查并给出警示,以便开发人员发现这些不足和隐患予以及时更正。
代码审查和语法错误检查是两个不同层次的概念。语法错误是低层次、强制性的检查,任何违反语法的程序都是无法通过编译的,也就是说可运行的程序必须是语法正确的。而代码审查是高级别,非强制性的检查,它对语法正确的程序施加了更高更严格的要求,从而提升程序的可读性、降低因变量命名、方法定义、程序逻辑的不完整性等问题而导致程序的潜在出错机率,增加程序的可维护性和健壮性。
林林总总的Java编程规范、编程范式以及编程经验都致力于提升代码质量,程序性能,软件维护性等非语法方法的课题,JBuilder 2005代码审查即是将各种行之有效的编程规范、范式、经验施加于你的程序中,以使你的程序遵守这些业已被大量的实践证明是成功的编程准则。
JBuilder 2005在默认的情况下设置的代码审查机制即是Sun的代码编程规范,此外还提供了大量可供选择的审查规则,你可以根据需要激活或关闭这些审查的规则。
对于初学者来说,代码审查无疑是学习和工作的良师益友,JBulder 2005通过即时的代码审查达到了对开发人员"监督匡正、笃行扶弱"的作用。开发人员也可以通过代码审查所反馈的问题,学习有关语法之外更多的编程要求和经验。
阅读导航
一、使用代码审查
在默认情况下,JBuilde 2005未激活代码审查的功能,可以通过Project->Project Properties...->Code Audits调用代码审查的设置页。
二、代码风格审查
往往有些程序员热衷于将Java的语法发挥到极致,以资其对Java语法精通的凭据。但在需要充分协作沟通的软件项目中,简洁明了,清晰易懂将会受到推崇,晦涩难懂的语句将会受到奚落。故大部分的软件公司的规范都对语句的精简明了提出了要求。JBuilder 2005代码审查可以在一定程度上帮助公司落实和贯彻这一要求。
三、声明审查
成员变量和局部变量的隐藏,常常会使开发人员张冠李戴,犯一些不经意的错误,而子类隐藏父类的成员和静态变量常常是由于没有注意到父类中已经具有相同的名字而引起的,由此而生产的程序Bug由于其隐身性强,是很难被发现,JBuilder 2005提供几个对声明进行审查的工具。
四、命名风格
良好的命名风格在遵守Java命名语法之上,对命名提出了更高的要求,良好的命名风格必须遵守Java的命名规则
五、潜在错误审查
由于流程控制语句语法的特殊性,编写程序时需要特别注意,否则将会埋下祸根,JBuilder从多个方面对这些语句进行审查。
六、规避各种画蛇添足
JBuilder 2005代码审查功能的强大还在于能够判断多余的import包引入、不必要的强制类型转换、无用成员、多余的接口修饰符等。
七、其他
在程序中,由于种种原因存在无效表达式,或者程序永远不能使用的程序段,对于这些无用的代码,JBuilder 2005提供的代码审查功能也能查出来,并提醒程序员。
总结
JBuilder 2005提供了语法之上的代码审查功能,使用好代码审查功能不但可以增强程序代码的简洁性、可读性,还可以尽早发现潜在的编码错误,防患于未然。
JBuilder 2005代码审查功能无疑是一项开创性的工作,将对程序开发产生深远的影响,也是智能开发工具的一个发展方向。
|
|
使用Jbuilder 2005代码审查
在默认情况下,JBuilde 2005未激活代码审查的功能,可以通过Project->Project Properties...->Code Audits调用代码审查的设置页,如图1所示:
勾选Code Audits设置页中的"Enable Code Audits"激活当前工程的代码审查功能。Code Audits设置页的左边是一棵代码审查规则项的树,分为两级,第一级为审查规则项的归类,点开第一级的节点,第二级的各节点为具体的一个规则项,可以根据需要勾选可取消这些审查的规则。
点击规则项,在Code Audits设置页的右边显示出了该规则的详细描述信息并提供了实例,方便开发人员学习和理解。
在激活代码审查规则后,JBuilder 2005实时地审查编辑器中当前编写的程序文件,并在违反审查规则代码附近的控制槽上标注 ,违反规则代码的关键处将以一条粉红色的下划波浪线标识出来,此外在结构窗格的Warning文件夹下列出当前程序所有违反审查规则的代码,如图2所示:
审查结果项描述了代码中存在的问题的简要描述,通过这个提示和编译器控制槽上的 标识,点选审查结果项时,编辑器中相应的代码内容将以下划虚线形式显示,通过查看相应的代码,开发人员将能够快速发现问题所在。更正问题后,对应的审查警告将自动从Warning文件夹中清除。
代码风格审查
1、"switch"必须带一个default语句
根据Sun的编码规范,每个switch流程控制语句都必须带一个default分支,以保证逻辑分支的完整性。在默认情况下该审查项未激活,对应的设置项是"Coding Style" 下的"'switch' Statement Should Include a Default Case"。
代码清单 1 所有switch必须带default分支
1. switch (formatType) 2. { 3. case 1: 4. formatStr = "yyyyMMddHHmmss"; 5. break; 6. case 2: 7. formatStr = "yyyy'-'MM'-'dd HH:mm:ss"; 8. break; 9. case 3: 10. formatStr = "yyyy.MM.dd HH:mm:ss"; 11. break; 12. case 4: 13. formatStr = "yyyy'年'MM'月'dd HH:mm:ss"; 14. break; 15. default: 16. formatStr = "yyyy'-'MM'-'dd HH:mm:ss"; 17. } |
如果没有第15~16行的default代码,代码审查将给出警告。
提示:
可以通过Ctrl+J 调用switch代码模板录入的switch流程控制语句代码块将带一个default分支,这样,不但加速了编码的录入效率还保证了代码块的规范性。
2、应通过类名引用静态成员
类中所有的静态方法或变量都应该通过类名来引用,如果通过类的实例来引用这些静态的成员将影响到程序的可读性。如果通过类名来引用静态变量,将容易分辨出这些成员的静态属性。因为类静态成员变量在JVM中仅存在一份,而非每个对象实例各自一份,因此静态成员变量可以看成类的成员。
代码清单 2 关于静态成员的引用
1. public class ASMO1 2. { 3. void func() 4. { 5. ASMO1 obj1 = new ASMO1(); 6. ASMO2 obj2 = new ASMO2(); 7. obj1.attr = 10; //应更正为ASMO1.attr 8. obj2.attr = 20; //应更正为ASMO2.attr 9. obj1.oper(); //应更正为ASMO1. oper(); 10. obj2.oper(); //应更正为ASMO2. oper(); 11. this.attr++; //应更正为ASMO2. attr++; 12. this.oper(); //应更正为ASMO2 oper(); 13. } 14. 15. static int attr; 16. static void oper() 17. {} 18. } 19. 20. class ASMO2 21. { 22. static int attr; 23. static void oper() 24. {} 25. } |
该审查规则对应的设置项是"Coding Style" 下的"Accessing Static Members by the Descendant Class Name"。
3、避免复杂晦涩代码
往往有些程序员热衷于将Java的语法发挥到极致,以资其对Java语法精通的凭据。如果是为了练习语法、理解语法,无可厚非。但如果在需要充分协作沟通的软件项目中,简洁明了,清晰易懂将会受到推崇,晦涩难懂的语句将会受到奚落。
故此,大部分的软件公司的规范都对语句的精简明了提出了要求。JBuilder 2005代码审查可以在一定程度上帮助公司落实和贯彻这一要求。
代码清单3演示了晦涩的赋值语句及替代的写法:
代码清单 3 复杂晦涩的赋值语句
1. int i = 0; 2. int j = 0; 3. int k = 0; 4. int l = 0; 5. i *= ++j; 6. //应更改为: 7. //++j; 8. //i *= j; 9. 10. k = j = 10; 11. //应更改为: 12. //k = 10; 13. //j = 10; 14. 15. l = j += 15; 16. //应更改为: 17. //j += 15; 18. //l = j; 19. 20. i = j++ +20; 21. //应更改为: 22. //i = j + 20; 23. //j++; 24. 25. i = (j = 25) + 30; 26. //应更改为: 27. //j = 25; 28. //i = j + 30; 29. 30. i = j++ + 20; 31. //应更改为: 32. //i = j + 20; 33. //j++; 34. 35. i = (j = 25) + 30; 36. //应更改为: 37. //j = 25; 38. //i = j + 30; |
JBuilder 2005 初始状态下没有激活对复杂的赋值语句的审查,该审查内容对应"Coding Style"下的"Complex Assignment"设置项。
除需要注意赋值语句外,由于for循环控制语句的高度灵活性,所以for()中的代码往往是复杂晦涩代码的乐园,在for语句中以逗号分隔的赋值语句最多不应超过3个:
代码清单 4 复杂的for语句
1. for (i = 0, j = 0, k = 10, l = -1; i < 10; i++, j++, k--, l += 2) 2. { 3. //do something 4. } 5. //应改写成下面的样式 6. //l = -1; 7. //for (i = 0, j = 0, k = 10; i < cnt; i++, j++, k--) 8. //{ 9. // //do something 10. // l += 2; 11. //} |
该审查内容对应对应"Coding Style"下的"Complex Initialization or Update Clauses in 'for' Loops"设置项。
4、尽量使用赋值运算符
在可能的情况下使用赋值运行符(=, /=, %=, +=, -=, <<=, >>=, >>>=, &=, ^=, 和|=),因为这些语句能够提高编码录入的速度,增强代码的简洁性,同时赋值运行符使某些编辑器运行得更快。
代码清单 5 使用赋值运行符
1. void oper () { 2. int i = 0; 3. i = i + 20; 4. i = 30 * i; 5. } 6. //应改写成 7. //void oper () 8. //{ 9. // int i = 0; 10. // i += 20; 11. // i *= 30; 12. //} |
该审查内容对应"Coding Style"下的"Use Abbreviated Assignment Operator"的设置项。
5、其他代码风格的审查
1) 不应将多行语句写在同一行代码中。该审查内容对应"Coding Style"下的"Multiple Statements on One Line"设置项。
2) 代码块应以"{}"框起来,虽然增长了代码,但代码结构性更强。该审查内容对应"Coding Style"下的"Place Statement in Block" 设置项。
3) 声明长整型使用大写的"L",而非小写的"l",因为后者和数字1相似。该审查内容对应"Coding Style"下的"Use 'L' instead of 'l' at the End of Integer Constants"设置项。
代码清单6说明了上述的审查项:
代码清单 6 其他代码风格的审查
1. i++; 2. j++; 3. //应更改为 4. // i++; 5. // j++; 6. 7. if (val < 0) 8. return; 9. while (val >= 10) 10. val /= 10; 11. //应更改为 12. //if (val < 0) 13. //{ 14. // return; 15. //} 16. //while (val >= 10) 17. //{ 18. // val /= 10; 19. //} 20. 21. void func () { 22. long var = 0x0001111l; 23. } 24. //应更改为 25. void func () { 26. long var = 0x0001111L; 27. } |
此外,JBuilder 2005还提供了众多的代码风格审查项,读者需要根据实际需要出发,自决取舍。
声明审查
1、避免命名覆盖
命名隐藏的审查有以下几种情况:
1) 类成员变量被局部变量隐藏:因类方法体中的局部变量和类成员变量具有相同的名字,而使成员变量被屏蔽。一般情况下,类构造函数或赋值方法的入参和类中的成员变量保持相同的名字,类的成员变量通过this显式标识,这种情况下该审查规则不会警示。该审查内容对应于"Declaration Style"下的"Hiding Names"设置项。
代码清单 7 局部变量隐藏成员变量
1. public class HideName 2. { 3. int index; 4. void func() 5. { 6. int index;//隐藏了成员变量index,应改成另一个名字,如int newIndex; 7. // do something 8. } 9. void setIndex(int index) 10. { 11. this.index = index; //该语句行中带this显式引用成员变量进行赋值,审查规则将不报警 12. index++;//该语句行没有this显式引用,审查规则将报警 13. } 14. } |
2) 子类成员变量隐藏父类成员变量:子类成员变量和可继承的父类成员变量名字相同。该审查内容对应于"Declaration Style"下的"Hiding Inherited Field"设置项。
代码清单 8 子类成员变量隐藏父类成员变量
1. class Window 2. { 3. protected int style; 4. } 5. 6. class Button extends Window 7. { 8. protected int style;//具有和父类相同的成员变量,应改为另一个名字,如anStyle 9. } |
3) 子类覆盖父类静态方法:和非静态的方法覆盖不一样,静态的父类方法不应被子类覆盖,该审查内容对应于"Declaration Style"下的"Hiding Inherited Static Methods"。
代码清单 9子类覆盖父类静态方法
1. class Animal 2. { 3. static void oper1(){} 4. static void oper2(){} 5. } 6. 7. class Elephant extends Animal 8. { 9. static void oper1() {}//隐藏了父类中的静态方法,应取另一个名字,如anOper1() 10. static void oper2() {}//隐藏了父类中的静态方法,应取另一个名字,如anOper2() 11. } |
成员变量和局部变量的隐藏,常常会使开发人员张冠李戴,犯一些不经意的错误,而子类隐藏父类的成员和静态变量常常是由于没有注意到父类中已经具有相同的名字而引起的,由此而生产的程序Bug由于其隐身性强,是很难被发现,该审查项帮助你规避这一问题。
2、使用适合的修饰符
static,final,可视域等修饰符可以用于修饰,类的成员变量、方法及内部类,使用恰当的修饰符,类的封装性、承继性将得到增强,同时还防止了错误的调用。修饰符的审查主要包括以下3点:
1) 常量应该被标识为final:这样可以阻止程序对其值进行更改,也可以防止子类的覆盖。该审查内容对应"Declaration Style"下的"Constant Variables Should Be Final"设置项。
2) 不被外部调用的成员应该声明为private:该审查项主查为了强化类的封装性和内聚性,使类对应的接口更加清晰。该审查项并不对public的成员生效,被标识为public的成员将被看成是希望向外开放的。该审查内容对应"Declaration Style"下的"Member Can be made Private"设置项。在接到该审查项的报警时,开发人员需要根据实际情况作出判断,以将确实可以设置为private的成员改正过来。
3) 可设置为static的成员:JBuilde r2005分析哪些成员变量及成员内部类可以置为static:即那些在静态环境下使用的成员变量和没有引用容器类非静态成员和方法的内部类。该审查内容对应"Declaration Style"下的"Member Can be made Static"设置项。
3、有关子类覆盖的审查
JBuilder将对继承覆盖中的以下几个方面进行审查:
1) equals()和hashcode()方法必须同时覆盖:类覆盖了Object类中所定义的equals(Object obj),同时也必须覆盖Object类中所定义的hashCode()方法,因为必须保证用equals(Object obj)判断为相同的对象拥有相同的hashCode值。该审查内容对应"Declaration Style"下的"Override Hash code when you override Equals"设置项。
2) 将父类中的非抽象类覆盖成抽象类:没有理由将父类的非抽象类覆盖成子类的抽象类,甚至可以断定这是编码上的偏误。该审查内容对应"Declaration Style"下的"Overriding a Non-Abstract Method with an Abstract Method"设置项。
3) 在子类中声明和父类相同的private方法:private方法是不能被覆盖的,一般情况下,可以被子类覆盖的方法是protected或public。该审查内容对应"Declaration Style"下的"Overriding a Private Method"设置项。
4、代码排列及先后顺序
对类文件的代码进行良好的组织,可以增强代码的可维护性和可读性,JBuilder 2005对代码的排列及先后顺序进行以下方面的审查:
1) 类成员的排列:根据Sun的代码编程惯例,成员的先后顺序以可视域从大到小排列,即: public->protected->默认->private。类中的成员按如下方式排列:
2)静态成员变量排在最前面,静态成员间以可视域从大到小排列。
3)第二位是实例成员变量,实例成员变量间以可视域从大到小排列。
4)第三位是构造函数。
5)第四位是成员方法
该审查内容对应"Declaration Style"下的"Order of Declaration of Class Members"设置项。
i 将重载方法列在一起:类的重载方法完成相似的功能,具有相同的方法名,将它们列在一起可以增强程序的可读性,且不容易遗漏掉某个功能。该审查内容对应"Declaration Style"下的"Place Methods with Same Name Together"设置项。
ii 将public类放在前面:对于包含多个类的程序文件,应该把public的类放在前面。该审查内容对应"Declaration Style"下的"Place Public Class First"设置项。
命名风格
1、取消不良命名习惯
良好的命名风格在遵守Java命名语法之上,对命名提出了更高的要求,良好的命名风格必须遵守以下的命名规则:
1) 类或接口必须以大写字母打头。
2) 方法、属性、成员变量、局部变量以小写字母打头,且不以"_"或"$"打头。
3) 常量的所有字母都大写。
4) 异常类以Exception结尾。
良好命名对应"Naming Style"下的"Naming Conventions"设置项。
2、建立和国际接轨的包名
包名应该用顶级域名打头,如com,org,edu等,或者用国家代码如cn,ru等。
一般公司和组织都对包名前两级都有严格的规则,如IBM公司的类以com.ibm打头,apache以org.apache打头,第三级才是具体的项目或产品名称,这样的包命名就象三维网的URL命名一样已经成为了一种国际通用的准则。对此没有作出严格规定的公司,开发负责人应该推动建立起符合这一命名规则的规范。
该审查项,默认情况下没有激活,可以通过"Naming Style"下的"Package Name"的设置项激活。
3、避免用过于简单的变量名
除了循环体中的临时变量,及一些没有特殊意义的常见数据类型,应该尽量避免使用一个字符作为变量。那些无特殊意义且常见的数据类型,所选取的单字符变量名必须按表1进行命名:
表 1 变量本身无意义的常见数据类型允许的单字符变量
常见数据类型 |
单字符变量名 |
常见数据类型 |
单字符变量名 |
byte |
b |
double |
d |
char |
c |
Object |
o |
int |
i,j,k |
String |
s |
long |
l |
Exception |
e |
float |
f |
|
|
此外,为了减少潜在的冲突,避免不必要的混淆,不允许以大写域名或国家代码作变量名。
代码清单 10 取有意义的变量名
1. void method(double d) 2. { 3. int i; 4. Exception e; 5. char s;//应该改为c 6. Object f;//应该改为o 7. String k;//应该改为s 8. Object UK;//和英国国家代码相同,应改为其他的名字,如ukObj 9. Object COM;//和域名相同,应改为其他的名字,如obj_1 10. } |
该审查项,在默认情况下没有激活,可以通过"Naming Style"下的"Use Conventional Variable Names"的设置项激活。
潜在错误审查
1、聚焦switch
由于switch流程控制语句语法的特殊性,编写程序时需要特别注意,否则将会埋下祸根,JBuilder从以下3个方面对switch进行审查:
1) 有无对前面没有break语句的case从句作标识:根据Sun编码惯例,程序入口点从一个case进入,直接到达下一个case代码段,即前一个case没有对应的break语句时,在跨过的地方必须给出一个显示的注释,表示是特定流程控制的要求,而非无意遗漏。来看下面的代码:
代码清单 11 没有break的case从句
1. switch (c) { 2. case '+': 3. ... 4. break; 5. case '-': 6. ... 7. case 'n': 8. ... 9. case ' ': case '/t': 10. ... 11. break; 12. } |
假设在代码清单11的第7行之前,是因为疏忽而遗漏了一个break语句,第9行之前是逻辑需要而故意不加break语句,则将代码更改为:
代码清单 12 更正的switch代码
1. switch (c) { 2. case '+': 3. ... 4. break; 5. case '-': 6. ... 7. break; 8. case 'n': 9. ... 10. //继续运行到下面 11. case ' ': case '/t': 12. ... 13. break; 14. } |
该审查内容对应于"Possible Errors"下的"Break Statement is Missing before Case clause"设置项。
2) 在switch中出现非case的标签:在Java语句中有两个标签,即case分支标签,另一个则是语句标签,如果case分支标签语句误删或遗漏了case关键字,则case分支标签将变成语句标签,而编译器无法识别这个错误。
代码清单 13 case分支中缺少case而使标签发生质变
1. public class CaseLabel 2. { 3. /**点*/ 4. public static final int POINT = 1; 5. /**线*/ 6. public static final int LINE = 2; 7. /**多边形*/ 8. public static final int POLYGON = 3; 9. 10. public String getFigureType (int kind) 11. { 12. String tempName = null; 13. switch (kind) 14. { 15. case POINT: 16. LINE://该语句缺少case,编译器将其作为语句标签处理,并不会发生语法错误 17. //但该方法传入常量LINE时,将转到default分支中,而非到达这晨,故 18. //应该将该行语句更改为case LINE: 19. tempName = "POINT and LINE"; 20. break; 21. case POLYGON: 22. tempName = "POLYGON"; 23. break; 24. default: 25. tempName = "UNDEFINE"; 26. } 27. return tempName; 28. } 29. } |
该审查内容对应于"Possible Errors"下的"Non-Case Label in Switch statement"设置项。
3) 有错误嫌疑的break和continue:break和continue用于switch和循环中的跳转控制,break用于提前结束循环以及从switch中退出,break的这种"多态性"使得在循环体中内嵌switch语句时,常会带来一些隐患。即开发者本希望退出外层循环,结果却只退出内层的switch语句而已。JBuilder 2005对这项内容的审查包括以下方面:
switch内嵌于循环体中,且case从句中包含了不位于分支块最后位置的break语句。
switch内嵌于循环体中,且case从句既使用了break,又使用了continue,但两者的效果却是一样的。
break或continue语句中使用了不必要的语句标签。
请看下面的代码:
代码清单 14有错误嫌疑的break和continue
1. void scan(char[] arr) 2. { 3. loop: 4. for (int i = 0; i < arr.length; i++) 5. { 6. switch (arr[i]) 7. { 8. case '0':case '1':case '2':case '3':case '4': 9. //5~6的数字 10. case '5':case '6':case '7':case '8':case '9': 11. { 12. if (processDigit(arr[i])) 13. { 14. continue loop; //loop语句标签没有必要 15. } 16. else 17. { 18. break; // 该break不会结束for循环,应该使用break loop才可结束循环 19. } 20. } 21. case ' ':case '/t': 22. { 23. processWhitespace(arr[i]); 24. continue; // 应该使用break而非continue 25. } 26. default: 27. processLetter(arr[i]); 28. break; 29. } 30. } |
该审查内容对应于"Possible Errors"下的"Suspicious Break/Continue"设置项。
2、避免对浮点值进行等值逻辑判断
浮点数都是一定精度的数据,由于内部表示的误差,往往字面上相同的两个浮点数,其内部表示也不完全相同。故此应避免对浮点值数进行等值逻辑判断,而应采用逻辑比较判断。
代码清单 15 语句中包含浮点等值判断
1. void calc(double limit) 2. { 3. if (limit == 0.0)//应改为通过和较小值比较来判断,如if(Math.abs(limit) < 0.0000001) 4. { 5. System.out.println(" the float-point number is exactly 0"); 6. } 7. } |
该审查内容默认未激活可以通过"Possible Errors"下的"Suspicious Break/Continue"设置项来激活审查。
3、添加()清晰化复杂的表达式
写复杂的表达式时不应过度依赖运算操作符的计算优先顺序,而应养成使用"()"的好习惯,当一个逻辑表达式由多个逻辑运算组成时,应该用"()"划分不同的部分。
代码清单 16 用括号清晰化表达式
1. boolean a, b, c; 2. ... 3. if (a || b && c) //应该替换成if ((a || b) && c) 4. { 5. ... 6. } |
该审查内容默认未激活可以通过"Possible Errors"下的"Mixing Logical Operators Without Parentheses"设置项来激活审查。
4、字符串比较
Java初学者一个常犯的错误是使用"=="或"!="对字符串进行等值逻辑判断。使用"=="将判断两者否是指向相同的对象引用,而非判断两者是否具有值,应该使用equals()替代。
代码清单 17 用equals()替换"=="
1. public boolean equals(String s1, String s2) 2. { 3. return s1 == s2; //应改为return s1.equals(s2); 4. } |
该审查内容对应于"Possible Errors"下的"Use 'equals' Instead of '= ='"设置项。
规避各种画蛇添足
1、将布尔变量和布尔值比较
没有必要将布尔变量和布尔值进行比较,应该确保在逻辑表达式中不出现"true"或"false"这两个布尔字面值:
代码清单 18 避免在逻辑表达式中出现布尔字面值
1. boolean success = init(); 2. if (success == true) //应该更正为if(success) 3. { 4. ... 5. } |
该审查内容对应于"Superfluous Content"下的"Equality Operations on Boolean Arguments"设置项。
2、无用的成员
类中private的成员方法和成员变量不可能在外部类中调用,JBuilder 2005 如果发现private的成员变量或方法并没有在内部的protect或public方法中使用,即这个成员永远不会在运行期得到引用,而成为一个无用的成员变量和方法。审查机制将其标识为未使用的成员,并予以报警。
代码清单 19 无用的成员
1. public class Unuse 2. { 3. private String name; 4. public Object value; 5. 6. private Object getValue() 7. { 8. return value; 9. } 10. 11. private void print() 12. { 13. System.out.println(getValue() + " = " + value); 14. } 15. } |
代码清单19中name变量,getValue()及print()方法都是无用的方法,因为不可能通过外面的类访问到这些成员,Unuse也没有提供调用这些成员的接口,所以这些成员都可以从类中清除。
该审查内容对应于"Superfluous Content"下的"Member is Not Used"设置项。
3、多余的接口修饰符
接口都是抽象的,接口中定义的方法都是抽象且公有,即public abstract;接口中的常量都是public static final的。所以如果在接口定义、接口成员方法及接口常量声明时使用了这些修饰符则是多余的,JBuilder 2005对此作出审查,并报告这些多余的修饰。
代码清单 20 多余的接口修饰符
1. interface Colors { 2. public static final int RED = 1; 3. public abstract void getColorName(int color); 4. } |
代码清单20中粗体的修饰符都是多余的,应该去掉。
这些审查内容可以通过"Superfluous Content"下的"Obsolete Interface Modifiers"和 "Unnecessary Member Modifier"审查项来设置。
4、不必要的强制类型转换
"小类型"到"大类型"及子类到父类自动进行类型转换,无需加上强制类型转换的操作符,JBuilder 2005检查出这些不必要的类型转换。
代码清单 21 不必要的类型转换
1. class Animal {} 2. class Elephant extends Animal { 3. void func () { 4. int i; 5. float f = (float) i; 6. 7. Elephant e1; 8. Elephant e2 = (Elephant) e1; 9. 10. Animal a; 11. Elephant e; 12. a = (Animal) e; 13. } 14. } |
代码清单21中粗体的强制类型转换语句都是没有必要的,应该取消强制类型转换。
该审查内容对应"Superfluous Content"下的"Unnecessary type Cast"审查项。
5、多余的import包引入
该审查项帮助你构建优化的import语句段,当程序文件中通过import语句引用java.lang.*(编译器自动引入)、当前类所在的包、以及未使用的包或者重复引入包时,JBuilder2005都将进行警告。
优先import包引入语句最方便方法即是在编辑器中点击右键,在弹出的菜单中选择"Format All"菜单项,自动优化import包引入程序段的代码。可以通过Project->Project Properties...->Java Formating->Import代码格式化设置项完成优化包引入的设置。
该审查内容对应"Superfluous Content"下的"Import List Construction"审查项。
其他
1、无作为的表达式
无作为的表达式表现在以下两个方面:
1) 比较表达式总是返回相同的值。
代码清单 22 表达式产生恒值
1. void handleEvent(Event e){ 2. if (e != null) { 3. ... 4. if (e = = null) { // 该表达式的值永远都是false,因为进入这个代码段的e恒为非空 5. ... 6. } 7. } 8. } 9. 10. void putChar(char c, boolean isLetter, boolean isDigit) { 11. if (isDigit) { 12. boolean isLetterOrDigit = isLetter || isDigit;//该表达式的值永远都是true 13. ... 14. } 15. } |
该审查内容对应"Expressions"下的"Comparison always produces the Same Result"和"Expression Value is Constant"两审查项。
2) 无效的算术运算。
当进行加法和减法运算时,有一个操作数是0。
当进行乘法运算时,乘法或被被乘数为1。
当进行除法运算时,除数为1。
当进行取模运算时,左边的操作数的绝对值比右边操作数的绝对值小,此时x%y=x。
属性赋值时,将本身的值赋给自己。
代码清单 23 无效的算术运算
1. public class NoEffect 2. { 3. private String name; 4. private int index; 5. 6. NoEffect(String n, int index) 7. { 8. this.name = name; //将属性值赋给本身 9. this.index = index; 10. } 11. 12. int getPosition() 13. { 14. int base = 0; 15. return index + base; //和0相同 16. } 17. 18. int getModule() 19. { 20. int x = 1, y = 2; 21. return x % y;//左边操作数绝对值比右边操作数的小 22. } 23. } |
该审查内容对应"Expressions"下的"Operation has No Effect"审查项。
2、流程控制中存在不可到达的语句
有些流程控制由于测试条件恒为false,则流程中的程序无法到达。
代码清单 24 不可至的语句
1. int[] arr = new int[size]; 2. if (arr == null) //由于arr不为空,则该测试逻辑不可能通过,程序无法进入该程序块中 3. { 4. return null; 5. } |
该审查内容对应"Branches and Loops"下的"Statement is Unreachable" 审查项。
3、无用的流程标签
循环中标注了语句标签,则没用任何地方使用这个标签,即该标签为无用标签,应予以去除。
代码清单 25 无用的流程标签
1. int findItem(Object[] list, Object item) { 2. loop: //程序中没有任何地方使用该标签 3. for (int i = 0; i < list.length; i++) { 4. if (list[i].equals(item)) { 5. eturn i; 6. } 7. } 8. return -1; 9. } |
该审查内容对应"Branches and Loops"下的"Label is Not Used" 审查项。
总结
JBuilder 2005提供了语法之上的代码审查功能,使用好代码审查功能不但可以增强程序代码的简洁性、可读性,还可以尽早发现潜在的编码错误,防患于未然。
JBuilder 2005代码审查功能无疑是一项开创性的工作,将对程序开发产生深远的影响,也是智能开发工具的一个发展方向。