學(xué)習(xí)java的同學(xué)注意了!!! 學(xué)習(xí)過(guò)程中遇到什么問(wèn)題或者想獲取學(xué)習(xí)資源的話,歡迎加入Java學(xué)習(xí)交流群,群號(hào)碼:523047986 我們一起學(xué)Java!
代碼質(zhì)量概述
怎樣辨別一個(gè)項(xiàng)目代碼寫得好還是壞??jī)?yōu)秀的代碼和腐化的代碼區(qū)別在哪里?怎么讓自己寫的代碼既漂亮又有生命力?接下來(lái)將對(duì)代碼質(zhì)量的問(wèn)題進(jìn)行一些粗略的介紹。也請(qǐng)有過(guò)代碼質(zhì)量相關(guān)經(jīng)驗(yàn)的朋友提出寶貴的意見。
代碼質(zhì)量所涉及的5個(gè)方面,編碼標(biāo)準(zhǔn)、代碼重復(fù)、代碼覆蓋率、依賴項(xiàng)分析、復(fù)雜度分析。這5方面很大程序上決定了一份代碼的質(zhì)量高低。我們分別來(lái)看一下這5方面:
編碼標(biāo)準(zhǔn):這個(gè)想必都很清楚,每個(gè)公司幾乎都有一份編碼規(guī)范,類命名、包命名、代碼風(fēng)格之類的東西都屬于其中。
代碼重復(fù):顧名思義就是重復(fù)的代碼,如果你的代碼中有大量的重復(fù)代碼,你就要考慮是否將重復(fù)的代碼提取出來(lái),封裝成一個(gè)公共的方法或者組件。
代碼覆蓋率:測(cè)試代碼能運(yùn)行到的代碼比率,你的代碼經(jīng)過(guò)了單元測(cè)試了嗎?是不是每個(gè)方法都進(jìn)行了測(cè)試,代碼覆蓋率是多少?這關(guān)系到你的代碼的功能性和穩(wěn)定性。
依賴項(xiàng)分析:你的代碼依賴關(guān)系怎么樣?耦合關(guān)系怎么樣?是否有循環(huán)依賴?是否符合高內(nèi)聚低耦合的原則?通過(guò)依賴項(xiàng)分析可以辨別一二。
復(fù)雜度分析:以前有人寫的程序嵌套了10層 if else你信嗎?圈復(fù)雜度之高,讓人難以閱讀。通過(guò)復(fù)雜度分析可以揪出這些代碼,要相信越優(yōu)秀的代碼,越容易讀懂。
上面解釋了代碼質(zhì)量相關(guān)的5個(gè)方面,在實(shí)際開發(fā)環(huán)境中,已經(jīng)有很多工具為我們解決以上5個(gè)方面的問(wèn)題,下列5個(gè)eclipse插件分別對(duì)這5個(gè)問(wèn)題有很好的支持:
編碼標(biāo)準(zhǔn):CheckStyle 插件URL:http://eclipse-cs.sourceforge.net/update/
代碼重復(fù):PMD的CPD 插件URL:http://pmd.sourceforge.net/eclipse/
代碼覆蓋率:Eclemma 插件URL:http://update.eclemma.org
依賴項(xiàng)分析:JDepend 插件URL:http://andrei.gmxhome.de/eclipse/
復(fù)雜度分析:Eclipse Metric 插件URL:http://metrics.sourceforge.net/update
注:某些插件需要科學(xué)上網(wǎng)才能更新
編碼標(biāo)準(zhǔn)(CheckStyle的使用)
在eclipse上安裝好了CheckStyle插件后,我們來(lái)建一個(gè)類用它跑一下。這個(gè)類很簡(jiǎn)單,一個(gè)常見的用戶實(shí)體,包含了id,用戶名、密碼、郵件等屬性,并包含get set方法,一個(gè)標(biāo)準(zhǔn)的POJO。運(yùn)行CheckStyle檢查一下:
一個(gè)我們平時(shí)再普通不過(guò)的一個(gè)類,被checkstyle弄出這么多問(wèn)題,情何以堪,我們來(lái)看看究竟是什么情況?
看一下這些警告信息:
line 1、
,說(shuō)缺少package-info.java文件。
line 2、
,說(shuō)第一句注釋要以“.”結(jié)尾。
line 30、
,缺少java doc注釋。
line 35、
,getId不是繼承的方法,必須指定abstract,final或空。另外也缺少java doc注釋。
這個(gè)類基本就這四類毛病,缺少package-info.java文件,這個(gè)文件是做什么的呢?他是用來(lái)描述包注釋的類,有一定的特殊性,要想詳細(xì)了解請(qǐng)百度。如果對(duì)你的項(xiàng)目沒有太大的影響,可以忽略它。配置CheckStyle的方法我們等會(huì)再說(shuō)。第一句注釋要以“.”結(jié)尾,這看你的習(xí)慣,你確定需要這個(gè),你就保留,不需要就忽略。缺少java doc,對(duì)于java類的屬性來(lái)說(shuō),注釋是必要的,所以這個(gè)要保留。不是繼承的方法,需要加上final關(guān)鍵字,如果你有這個(gè)習(xí)慣,就保留,反之忽略。
我們這里只是建立了一個(gè)最簡(jiǎn)單的類用CheckStyle來(lái)檢查,隨著你的類代碼越來(lái)越多,邏輯越來(lái)越復(fù)雜,CheckStyle能檢查出來(lái)的毛病也越來(lái)越多。常見的CheckStyle錯(cuò)誤有這些:
1.Type is missing a javadoc commentClass 缺少類型說(shuō)明 2.“{” should be on the PRevious line “{” 應(yīng)該位于前一行 3.Methods is missing a javadoc comment 方法前面缺少javadoc注釋 4.Expected @throws tag for “Exception” 在注釋中希望有@throws的說(shuō)明 5.“.” Is preceeded with whitespace “.” 前面不能有空格 6.“.” Is followed by whitespace“.” 后面不能有空格 7.“=” is not preceeded with whitespace “=” 前面缺少空格 8.“=” is not followed with whitespace “=” 后面缺少空格 9.“}” should be on the same line “}” 應(yīng)該與下條語(yǔ)句位于同一行 10.Unused @param tag for “unused” 沒有參數(shù)“unused”,不需注釋 11.Variable “CA” missing javadoc 變量“CA”缺少javadoc注釋 12.Line longer than 80characters 行長(zhǎng)度超過(guò)80 13.Line contains a tab character 行含有”tab” 字符 14.Redundant “Public” modifier 冗余的“public” modifier 15.Final modifier out of order with the JSL suggestionFinal modifier的順序錯(cuò)誤 16.Avoid using the “.*” form of import Import格式避免使用“.*” 17.Redundant import from the same package 從同一個(gè)包中Import內(nèi)容 18.Unused import-java.util.list Import進(jìn)來(lái)的java.util.list沒有被使用 19.Duplicate import to line 13 重復(fù)Import同一個(gè)內(nèi)容 20.Import from illegal package 從非法包中 Import內(nèi)容 21.“while” construct must use “{}” “while” 語(yǔ)句缺少“{}” 22.Variable “sTest1” must be private and have accessor method 變量“sTest1”應(yīng)該是private的,并且有調(diào)用它的方法 23.Variable “ABC” must match pattern “^[a-z][a-zA-Z0-9]*$” 變量“ABC”不符合命名規(guī)則“^[a-z][a-zA-Z0-9]*$” 24.“(” is followed by whitespace “(” 后面不能有空格 25.“)” is proceeded by whitespace “)” 前面不能有空格
可以看出CheckStyle檢查出來(lái)的問(wèn)題,大多是編碼規(guī)則以及風(fēng)格上的問(wèn)題,這是編寫高質(zhì)量代碼最基本的。值得注意的是,我們將一些優(yōu)秀的開源代碼用CheckStyle來(lái)檢查也會(huì)檢查出不少問(wèn)題,這不能不說(shuō)這些開源不優(yōu)秀,而是每個(gè)公司組織有自己的編寫規(guī)范度,這個(gè)度既可以減少程序員的工作量又可以讓代碼的可讀性合格,但這個(gè)度不一樣符合CheckStyle的完整標(biāo)準(zhǔn)。所以我們一般使用CheckStyle都不會(huì)用他的默認(rèn)標(biāo)準(zhǔn),而是通過(guò)配置,制定適合自己的編碼規(guī)則。
自定義CheckStyle規(guī)則:
打開CheckStyle配置,新建一個(gè)配置,選擇外部配置文件。在這之前最好導(dǎo)出一個(gè)eclipse自帶的checkstyle配置文件(sun_checks.xml),然后重命名作為一個(gè)外部的配置導(dǎo)進(jìn)去,這么做的目的是導(dǎo)入之后可以修改相應(yīng)的配置,達(dá)到自定義配置的目的(因?yàn)閑clipse自帶的配置是加鎖的,不能修改)。導(dǎo)入之后,點(diǎn)擊右邊的“Configure”進(jìn)行編輯。
先去掉缺少package-info.java文件的提示
再將第一句注釋要以“.”結(jié)尾這個(gè)規(guī)則去掉,雙擊“Style javadoc”,將窗口內(nèi)“checkFirstSentence”勾選去掉。
對(duì)于實(shí)體類,屬性有了注釋,get set方法也不需要注釋了,雙擊“Method javadoc”將allowMissingPropertyJavadoc勾選中。
“getId不是繼承的方法,必須指定abstract,final或空”,如果你懶得在方法上加“final”,這條規(guī)則也可以去掉。
如果你不想每一個(gè)參數(shù)都加“final”,還需要把參數(shù)的final規(guī)則去掉:
另外還有一個(gè)錯(cuò)誤“'id' hides a field.”,原因是方法的參數(shù)和類里面定義的域重名了,但使用eclipse生成的get set方法都會(huì)這樣,所以可以忽略此項(xiàng)。
至此我們?cè)偈褂胏heckstyle檢查一篇,發(fā)現(xiàn)僅剩下屬性缺少注釋這個(gè)警告。
對(duì)每個(gè)屬性加上java doc注釋,所有問(wèn)題都清除了。以此類推,解決checkstyle問(wèn)題的方法就是:1、按規(guī)則解決代碼問(wèn)題;2、如果覺得這個(gè)問(wèn)題對(duì)你的項(xiàng)目質(zhì)量影響不大,則可以忽略它。
代碼重復(fù)(PMD的CPD的使用)
對(duì)于多人開發(fā)的項(xiàng)目,難以避免出現(xiàn)重復(fù)代碼的問(wèn)題,盡管我們盡量對(duì)共用的代碼進(jìn)行了封裝,但隨著需求的增加、人員技術(shù)水平差異、溝通不足等原因,重復(fù)代碼會(huì)越來(lái)越多。這不僅嚴(yán)重影響代碼質(zhì)量,也無(wú)形中增加了代碼量。
注:精簡(jiǎn)的程序和高復(fù)用度的代碼是我們一直追求的目標(biāo)。
PMD的CPD工具就是為檢查重復(fù)代碼而生的。右鍵項(xiàng)目--->PMD---->Find Suspect Cut and Paste,執(zhí)行重復(fù)代碼檢查:
檢查出來(lái)的重復(fù)代碼,可以雙擊查看。然后根據(jù)業(yè)務(wù)邏輯以及代碼特征,決定要不要做封裝、怎么封裝。
代碼覆蓋率(Eclemma的使用)
一份質(zhì)量合格的代碼,不僅包含功能程序本身也包含了對(duì)應(yīng)的測(cè)試代碼,Eclemma插件可以用來(lái)統(tǒng)計(jì)測(cè)試代碼覆蓋整體代碼中的比率,以此來(lái)評(píng)估代碼的功能性和穩(wěn)定性。
使用Junit編寫好測(cè)試用例之后,右鍵Coverage As--->Junit Test,運(yùn)行測(cè)試用例,Eclemma會(huì)統(tǒng)計(jì)出相關(guān)的代碼覆蓋率:
根據(jù)這個(gè)結(jié)果,你可以看出自己編寫的測(cè)試用例覆蓋到了那些代碼,而沒有覆蓋到的代碼,則有可能成為代碼質(zhì)量的盲區(qū)。
依賴項(xiàng)分析(JDepend的使用)
隨著程序業(yè)務(wù)邏輯的增加,代碼的依賴關(guān)系也變的越來(lái)越復(fù)雜,JDepend插件可以統(tǒng)計(jì)包和類的依賴關(guān)系,分析出程序的穩(wěn)定性、抽象性和是否存在循環(huán)依賴的問(wèn)題。右鍵包--->Run JDepend Analysis:
看一下這幾項(xiàng)指標(biāo):
CC(Number of Classes)
被分析package的具體和抽象類(和接口)的數(shù)量,用于衡量package的可擴(kuò)展性。如果一個(gè)類中實(shí)現(xiàn)了其他類,如實(shí)現(xiàn)了監(jiān)聽類,則監(jiān)聽類的數(shù)目也記錄在此。
AC(Abstract classes)
抽象類和接口的數(shù)量。
Ca(Afferent Couplings)
依賴于被分析package的其他package的數(shù)量,用于衡量pacakge的職責(zé)。即有多少包調(diào)用了它。
Ce(Efferent Couplings)
被分析package的類所依賴的其他package的數(shù)量,用于衡量package的獨(dú)立性。即它調(diào)用了多少其他包。
A(Abstractness)
被分析package中的抽象類和接口與所在package所有類數(shù)量的比例,取值范圍為0-1。
I(Instability)
I=Ce/(Ce+Ca),用于衡量package的不穩(wěn)定性,取值范圍為0-1。I=0表示最穩(wěn)定,I=1表示最不穩(wěn)定。即如果這個(gè)類不調(diào)用任何其他包,則它是最穩(wěn)定的。
D(Distance)
被分析package和理想曲線A+I(xiàn)=1的垂直距離,用于衡量package在穩(wěn)定性和抽象性之間的平衡。理想的package要么完全是抽象類和穩(wěn)定(x=0,y=1),要么完全是具體類和不穩(wěn)定(x=1,y=0)。取值范圍為0-1,D=0表示完全符合理想標(biāo)準(zhǔn),D=1表示package最大程度地偏離了理想標(biāo)準(zhǔn)。即你的包要么全是接口,不調(diào)用任何其他包(完全是抽象類和穩(wěn)定),要么是具體類,不被任何其他包調(diào)用。
Cycle
循環(huán)依賴的數(shù)量。
有個(gè)這個(gè)報(bào)告我們就可以有針對(duì)性的對(duì)代碼進(jìn)行設(shè)計(jì)和重構(gòu)。
復(fù)雜度分析(Metrics的使用)
對(duì)于閱讀代碼的人來(lái)說(shuō),越簡(jiǎn)單的代碼越好理解和維護(hù),如果你的代碼閱讀起來(lái)很費(fèi)勁或者你自己過(guò)段時(shí)間后再來(lái)看都看不懂,你就得想辦法解決下代碼的復(fù)雜度問(wèn)題了。Metrics插件可以幫你做到這點(diǎn)。
首先在Java透視圖下右鍵一個(gè)項(xiàng)目---->Properties,選擇Metrics,勾選Enble Metrics。
然后Window--->Show View---->Other---->Metrics View
打開Metrics視圖,點(diǎn)擊右上角運(yùn)行圖標(biāo),即可得到復(fù)雜度分析的結(jié)果:
可以根據(jù)復(fù)雜度指標(biāo),對(duì)自己的程序進(jìn)行優(yōu)化。
小結(jié)
本文介紹了和java代碼質(zhì)量相關(guān)的5個(gè)方面問(wèn)題,并介紹對(duì)應(yīng)eclipse插件的用法和作用。在我們實(shí)際開發(fā)中,盡量根據(jù)自己公司和團(tuán)隊(duì)的情況來(lái)制定一些檢查規(guī)則,來(lái)提高代碼質(zhì)量。并且在大多數(shù)情況下,會(huì)有兩個(gè)檢查環(huán)節(jié),即本地檢查和持續(xù)集成環(huán)境的檢查,我們常用的Hudson就可以集成很多插件。
學(xué)習(xí)Java的同學(xué)注意了!!! 學(xué)習(xí)過(guò)程中遇到什么問(wèn)題或者想獲取學(xué)習(xí)資源的話,歡迎加入Java學(xué)習(xí)交流群,群號(hào)碼:523047986 我們一起學(xué)Java!
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注