JBuilder2005代碼審查功能體驗
代碼審查作為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 '': 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 '': 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 '': 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代碼審查功能無疑是一項開創性的工作,將對程序開發產生深遠的影響,也是智能開發工具的一個發展方向。
”

