Java代碼檢查工具方案

1. 簡(jiǎn)介與引言

1.1 簡(jiǎn)介

本文首先介紹了靜態(tài)代碼分析的基本概念及主要技術(shù)蚌讼,隨后分別介紹了現(xiàn)有 4 種主流 Java 靜態(tài)代碼分析工具 (Checkstyle阴汇,F(xiàn)indBugs,PMD,Jtest),最后從功能泻帮、特性等方面對(duì)它們進(jìn)行分析和比較,希望能夠幫助 Java 軟件開(kāi)發(fā)人員了解靜態(tài)代碼分析工具友酱,并選擇合適的工具應(yīng)用到軟件開(kāi)發(fā)中晴音。

1.2 引言

在Java軟件開(kāi)發(fā)過(guò)程中,開(kāi)發(fā)團(tuán)隊(duì)往往要花費(fèi)大量的時(shí)間和精力發(fā)現(xiàn)并修改代碼缺陷缔杉。Java 靜態(tài)代碼分析(static code analysis)工具能夠在代碼構(gòu)建過(guò)程中幫助開(kāi)發(fā)人員快速锤躁、有效的定位代碼缺陷并及時(shí)糾正這些問(wèn)題,從而極大地提高軟件可靠性并節(jié)省軟件開(kāi)發(fā)和測(cè)試成本或详。目前市場(chǎng)上的 Java 靜態(tài)代碼分析工具種類繁多且各有千秋系羞,因此本文將分別介紹現(xiàn)有4種主流Java靜態(tài)代碼分析工具 (Checkstyle,F(xiàn)indBugs霸琴,PMD椒振,Jtest),并從功能梧乘、特性等方面對(duì)它們進(jìn)行分析和比較澎迎,希望能夠幫助 Java 軟件開(kāi)發(fā)人員了解靜態(tài)代碼分析工具,并選擇合適的工具應(yīng)用到軟件開(kāi)發(fā)中选调。

2. 靜態(tài)代碼分析工具簡(jiǎn)介

2.1 什么是靜態(tài)代碼分析

靜態(tài)代碼分析是指無(wú)需運(yùn)行被測(cè)代碼夹供,僅通過(guò)分析或檢查源程序的語(yǔ)法、結(jié)構(gòu)仁堪、過(guò)程哮洽、接口等來(lái)檢查程序的正確性,找出代碼隱藏的錯(cuò)誤和缺陷弦聂,如參數(shù)不匹配鸟辅,有歧義的嵌套語(yǔ)句,錯(cuò)誤的遞歸莺葫,非法計(jì)算匪凉,可能出現(xiàn)的空指針引用等等。在軟件開(kāi)發(fā)過(guò)程中捺檬,靜態(tài)代碼分析往往先于動(dòng)態(tài)測(cè)試之前進(jìn)行洒缀,同時(shí)也可以作為制定動(dòng)態(tài)測(cè)試用例的參考。統(tǒng)計(jì)證明欺冀,在整個(gè)軟件開(kāi)發(fā)生命周期中树绩,30%至70%的代碼邏輯設(shè)計(jì)和編碼缺陷是可以通過(guò)靜態(tài)代碼分析來(lái)發(fā)現(xiàn)和修復(fù)的。但是隐轩,由于靜態(tài)代碼分析往往要求大量的時(shí)間消耗和相關(guān)知識(shí)的積累饺饭,因此對(duì)于軟件開(kāi)發(fā)團(tuán)隊(duì)來(lái)說(shuō),使用靜態(tài)代碼分析工具自動(dòng)化執(zhí)行代碼檢查和分析职车,能夠極大地提高軟件可靠性并節(jié)省軟件開(kāi)發(fā)和測(cè)試成本瘫俊。

2.2 靜態(tài)代碼分析工具的優(yōu)勢(shì)

1. 幫助程序開(kāi)發(fā)人員自動(dòng)執(zhí)行靜態(tài)代碼分析鹊杖,快速定位代碼隱藏錯(cuò)誤和缺陷。

2. 幫助代碼設(shè)計(jì)人員更專注于分析和解決代碼設(shè)計(jì)缺陷扛芽。

3. 顯著減少在代碼逐行檢查上花費(fèi)的時(shí)間骂蓖,提高軟件可靠性并節(jié)省軟件開(kāi)發(fā)和測(cè)試成本。

2.3 Java靜態(tài)代碼分析理論基礎(chǔ)和主要技術(shù)

2.3.1 分缺陷模式匹配

缺陷模式匹配事先從代碼分析經(jīng)驗(yàn)中收集足夠多的共性缺陷模式川尖,將待分析代碼與已有的共性缺陷模式進(jìn)行模式匹配登下,從而完成軟件的安全分析。這種方式的優(yōu)點(diǎn)是簡(jiǎn)單方便叮喳,但是要求內(nèi)置足夠多缺陷模式被芳,且容易產(chǎn)生誤報(bào)。

2.3.2 類型推斷

類型推斷技術(shù)是指通過(guò)對(duì)代碼中運(yùn)算對(duì)象類型進(jìn)行推理馍悟,從而保證代碼中每條語(yǔ)句都針對(duì)正確的類型執(zhí)行畔濒。這種技術(shù)首先將預(yù)定義一套類型機(jī)制,包括類 型等價(jià)锣咒、類型包含等推理規(guī)則侵状,而后基于這一規(guī)則進(jìn)行推理計(jì)算。類型推斷可以檢查代碼中的類型錯(cuò)誤毅整,簡(jiǎn)單趣兄,高效,適合代碼缺陷的快速檢測(cè)毛嫉。

2.3.3 模型檢查

模型檢驗(yàn)建立于有限狀態(tài)自動(dòng)機(jī)的概念基礎(chǔ)之上诽俯,這一理論將被分析代碼抽象為一個(gè)自動(dòng)機(jī)系統(tǒng)妇菱,并且假設(shè)該系統(tǒng)是有限狀態(tài)的承粤、或者是可以通過(guò)抽象歸 結(jié)為有限狀態(tài)。模型檢驗(yàn)過(guò)程中闯团,首先將被分析代碼中的每條語(yǔ)句產(chǎn)生的影響抽象為一個(gè)有限狀態(tài)自動(dòng)機(jī)的一個(gè)狀態(tài)辛臊,而后通過(guò)分析有限狀態(tài)機(jī)從而達(dá)到代碼分析的 目的。模型檢驗(yàn)主要適合檢驗(yàn)程序并發(fā)等時(shí)序特性房交,但是對(duì)于數(shù)據(jù)值域數(shù)據(jù)類型等方面作用較弱彻舰。

2.3.4 數(shù)據(jù)流分析

數(shù)據(jù)流分析也是一種軟件驗(yàn)證技術(shù),這種技術(shù)通過(guò)收集代碼中引用到的變量信息候味,從而分析變量在程序中的賦值刃唤、引用以及傳遞等情況。對(duì)數(shù)據(jù)流進(jìn)行 分析可以確定變量的定義以及在代碼中被引用的情況白群,同時(shí)還能夠檢查代碼數(shù)據(jù)流異常尚胞,如引用在前賦值在后、只賦值無(wú)引用等帜慢。數(shù)據(jù)流分析主要適合檢驗(yàn)程序中的 數(shù)據(jù)域特性笼裳。

3. 現(xiàn)有主流Java靜態(tài)分析工具

3.1 Checkstyle

3.1.1 簡(jiǎn)介

Checkstyle是SourceForge的開(kāi)源項(xiàng)目唯卖,通過(guò)檢查對(duì)代碼編碼格式,命名約定躬柬,Javadoc拜轨,類設(shè)計(jì)等方面進(jìn)行代碼規(guī)范和風(fēng)格的檢查,從而有效約束開(kāi)發(fā)人員更好地遵循代碼編寫(xiě)規(guī)范允青。Checkstyle 提供了支持大多數(shù)常見(jiàn)IDE的插件橄碾,文本主要使用IntelliJ IDEA中的CheckStyle-IDEA插件。

3.1.2 內(nèi)置編程規(guī)范

Javadoc 注釋:檢查類及方法的 Javadoc 注釋

命名約定:檢查命名是否符合命名規(guī)范

標(biāo)題:檢查文件是否以某些行開(kāi)頭

Import 語(yǔ)句:檢查 Import 語(yǔ)句是否符合定義規(guī)范

代碼塊大小昧廷,即檢查類堪嫂、方法等代碼塊的行數(shù)

空白:檢查空白符,如 tab木柬,回車符等

修飾符:修飾符號(hào)的檢查皆串,如修飾符的定義順序

塊:檢查是否有空塊或無(wú)效塊

代碼問(wèn)題:檢查重復(fù)代碼,條件判斷眉枕,魔數(shù)等問(wèn)題

類設(shè)計(jì):檢查類的定義是否符合規(guī)范恶复,如構(gòu)造函數(shù)的定義等問(wèn)題

3.1.3 在idea中集成CheckStyle

File->Setting->Plugins至下圖界面,搜索CheckStyle-IDEA速挑,點(diǎn)擊安裝谤牡。

image.png

3.1.4 在idea中使用CheckStyle

第一步,使CheckStyle在idea中生效

settings->Editor->Inspections->CheckStyle

image.png

第二步姥宝,添加配置文件翅萤,即為CheckStyle配置檢測(cè)的規(guī)范,設(shè)定需要的代碼規(guī)范

以下是配置文件的一個(gè)樣本:

<?xml version="1.0"?>

<!DOCTYPE module PUBLIC

        "-//Puppy Crawl//DTD Check Configuration 1.3//EN"

        "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">

<module name="Checker">

    <!--

        If you set the basedir property below, then all reported file

        names will be relative to the specified directory. See

http://checkstyle.sourceforge.net/5.x/config.html#Checker

        <property name="basedir" value="${basedir}"/>

    -->

    <!-- 檢查每個(gè)包中是否有java注釋文件腊满,默認(rèn)有package-info.java -->

    <!-- <module name="JavadocPackage"/> -->

    <!-- 檢查文件是否以一個(gè)空行結(jié)束 -->

    <module name="NewlineAtEndOfFile"/>

    <!-- 檢查property文件中是否有相同的key -->

    <module name="Translation"/>

    <!-- 文件長(zhǎng)度不超過(guò)1500行 -->

    <module name="FileLength">

        <property name="max" value="1500"/>

    </module>

    <!-- 檢查文件中是否含有'\t' -->

    <module name="FileTabCharacter"/>

    <!-- Miscellaneous other checks. -->

    <module name="RegexpSingleline">

        <property name="format" value="\s+$"/>

        <property name="minimum" value="0"/>

        <property name="maximum" value="0"/>

        <property name="message" value="Line has trailing spaces."/>

    </module>

    <!-- 每個(gè)java文件一個(gè)語(yǔ)法樹(shù) -->

    <module name="TreeWalker">

        <!-- 注釋檢查 -->

        <!-- 檢查方法和構(gòu)造函數(shù)的javadoc -->

        <module name="JavadocMethod">

            <property name="tokens" value="METHOD_DEF" />

        </module>

        <!-- 檢查類和接口的javadoc套么。默認(rèn)不檢查author和version tags -->

        <module name="JavadocType"/>

        <!-- 檢查變量的javadoc -->

        <module name="JavadocVariable"/>

        <!-- 檢查javadoc的格式 -->

        <module name="JavadocStyle">

            <property name="checkFirstSentence" value="false"/>

        </module>

        <!-- 檢查T(mén)ODO:注釋 -->

        <module name="TodoComment"/>

        <!-- 命名檢查 -->

        <!-- 局部的final變量,包括catch中的參數(shù)的檢查 -->

        <module name="LocalFinalVariableName" />

        <!-- 局部的非final型的變量碳蛋,包括catch中的參數(shù)的檢查 -->

        <module name="LocalVariableName" />

        <!-- 包名的檢查(只允許小寫(xiě)字母)胚泌,默認(rèn)^[a-z]+(\.[a-zA-Z_][a-zA-Z_0-9_]*)*$ -->

        <module name="PackageName">

            <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$" />

            <message key="name.invalidPattern" value="包名 ''{0}'' 要符合 ''{1}''格式."/>

        </module>

        <!-- 僅僅是static型的變量(不包括static final型)的檢查 -->

        <module name="StaticVariableName" />

        <!-- Class或Interface名檢查,默認(rèn)^[A-Z][a-zA-Z0-9]*$-->

        <module name="TypeName">

            <property name="severity" value="warning"/>

            <message key="name.invalidPattern" value="名稱 ''{0}'' 要符合 ''{1}''格式."/>

        </module>

        <!-- 非static型變量的檢查 -->

        <module name="MemberName" />

        <!-- 方法名的檢查 -->

        <module name="MethodName" />

        <!-- 方法的參數(shù)名 -->

        <module name="ParameterName " />

        <!-- 常量名的檢查(只允許大寫(xiě))肃弟,默認(rèn)^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$ -->

        <module name="ConstantName" />

        <!-- 定義檢查 -->

        <!-- 檢查數(shù)組類型定義的樣式 -->

        <module name="ArrayTypeStyle"/>

        <!-- 檢查方法名玷室、構(gòu)造函數(shù)、catch塊的參數(shù)是否是final的 -->

        <!-- <module name="FinalParameters"/> -->

        <!-- 檢查long型定義是否有大寫(xiě)的“L” -->

        <module name="UpperEll"/>

        <!-- import檢查-->

        <!-- 避免使用* -->

        <module name="AvoidStarImport"/>

        <!-- 檢查是否從非法的包中導(dǎo)入了類 -->

        <module name="IllegalImport"/>

        <!-- 檢查是否導(dǎo)入了多余的包 -->

        <module name="RedundantImport"/>

        <!-- 沒(méi)用的import檢查笤受,比如:1.沒(méi)有被用到2.重復(fù)的3.import java.lang的4.import 與該類在同一個(gè)package的 -->

        <module name="UnusedImports" />

        <!-- 長(zhǎng)度檢查 -->

        <!-- 方法不超過(guò)150行 -->

        <module name="MethodLength">

            <property name="tokens" value="METHOD_DEF" />

            <property name="max" value="150" />

        </module>

        <!-- 方法的參數(shù)個(gè)數(shù)不超過(guò)5個(gè)穷缤。 并且不對(duì)構(gòu)造方法進(jìn)行檢查-->

        <module name="ParameterNumber">

            <property name="max" value="10" />

            <property name="ignoreOverriddenMethods" value="true"/>

            <property name="tokens" value="METHOD_DEF" />

        </module>

        <!-- 空格檢查-->

        <!-- 方法名后跟左圓括號(hào)"(" -->

        <module name="MethodParamPad" />

        <!-- 在類型轉(zhuǎn)換時(shí),不允許左圓括號(hào)右邊有空格箩兽,也不允許與右圓括號(hào)左邊有空格 -->

        <module name="TypecastParenPad" />

        <!-- Iterator -->

        <!-- <module name="EmptyForIteratorPad"/> -->

        <!-- 檢查尖括號(hào) -->

        <!-- <module name="GenericWhitespace"/> -->

        <!-- 檢查在某個(gè)特定關(guān)鍵字之后應(yīng)保留空格 -->

        <module name="NoWhitespaceAfter"/>

        <!-- 檢查在某個(gè)特定關(guān)鍵字之前應(yīng)保留空格 -->

        <module name="NoWhitespaceBefore"/>

        <!-- 操作符換行策略檢查 -->

        <module name="OperatorWrap"/>

        <!-- 圓括號(hào)空白 -->

        <module name="ParenPad"/>

        <!-- 檢查分隔符是否在空白之后 -->

        <module name="WhitespaceAfter"/>

        <!-- 檢查分隔符周圍是否有空白 -->

        <module name="WhitespaceAround"/>

        <!-- 修飾符檢查 -->

        <!-- 檢查修飾符的順序是否遵照java語(yǔ)言規(guī)范津肛,默認(rèn)public、protected比肄、private快耿、abstract囊陡、static、final掀亥、transient撞反、volatile、synchronized搪花、native遏片、strictfp -->

        <module name="ModifierOrder"/>

        <!-- 檢查接口和annotation中是否有多余修飾符,如接口方法不必使用public -->

        <module name="RedundantModifier"/>

        <!-- 代碼塊檢查 -->

        <!-- 檢查是否有嵌套代碼塊 -->

        <module name="AvoidNestedBlocks"/>

        <!-- 檢查是否有空代碼塊 -->

        <module name="EmptyBlock"/>

        <!-- 檢查左大括號(hào)位置 -->

        <module name="LeftCurly"/>

        <!-- 檢查代碼塊是否缺失{} -->

        <module name="NeedBraces"/>

        <!-- 檢查右大括號(hào)位置 -->

        <module name="RightCurly"/>

        <!-- 代碼檢查 -->

        <!-- 檢查是否在同一行初始化 -->

        <!-- <module name="AvoidInlineConditionals"/> -->

        <!-- 檢查空的代碼段 -->

        <module name="EmptyStatement"/>

        <!-- 檢查在重寫(xiě)了equals方法后是否重寫(xiě)了hashCode方法 -->

        <module name="EqualsHashCode"/>

        <!-- 檢查局部變量或參數(shù)是否隱藏了類中的變量 -->

        <module name="HiddenField">

            <property name="tokens" value="VARIABLE_DEF"/>

        </module>

        <!-- 檢查是否使用工廠方法實(shí)例化 -->

        <module name="IllegalInstantiation"/>

        <!-- 檢查子表達(dá)式中是否有賦值操作 -->

        <module name="InnerAssignment"/>

        <!-- 檢查是否有"魔術(shù)"數(shù)字 -->

        <module name="MagicNumber">

            <property name="ignoreNumbers" value="0, 1"/>

            <property name="ignoreAnnotation" value="true"/>

        </module>

        <!-- 檢查switch語(yǔ)句是否有default -->

        <module name="MissingSwitchDefault"/>

        <!-- 檢查是否有過(guò)度復(fù)雜的布爾表達(dá)式 -->

        <module name="SimplifyBooleanExpression"/>

        <!-- 檢查是否有過(guò)于復(fù)雜的布爾返回代碼段 -->

        <module name="SimplifyBooleanReturn"/>

        <!-- 類設(shè)計(jì)檢查 -->

        <!-- 檢查類是否為擴(kuò)展設(shè)計(jì)l -->

        <!-- <module name="DesignForExtension"/> -->

        <!-- 檢查只有private構(gòu)造函數(shù)的類是否聲明為final -->

        <module name="FinalClass"/>

        <!-- 檢查工具類是否有putblic的構(gòu)造器 -->

        <module name="HideUtilityClassConstructor"/>

        <!-- 檢查接口是否僅定義類型 -->

        <module name="InterfaceIsType"/>

        <!-- 檢查類成員的可見(jiàn)度 -->

        <module name="VisibilityModifier"/>

    </module>

</module>

步驟:首先在本地新建一個(gè)XML文件撮竿,將上面的代碼保存到XML文件中吮便,打開(kāi) settings->Other Settings->CheckStyle,如下圖幢踏,點(diǎn)擊+

image.png

在彈出的小窗口中選擇我們剛才保存到本地的配置文件


image.png

點(diǎn)擊Next后點(diǎn)擊Finsh髓需,完成配置。

第三步房蝉,測(cè)試我們配置的CheckStyle是否生效

首先僚匆,選擇要測(cè)試的代碼文件,然后右擊選擇Check Current File搭幻,

image.png

然后選擇我們配置的規(guī)則咧擂,點(diǎn)擊之后,我們可以看到檀蹋,CheckStyle幫我們指出了代碼中的不規(guī)范松申。

image.png

3.2 FindBugs

3.2.1 簡(jiǎn)介

FindBugs 是由馬里蘭大學(xué)提供的一款開(kāi)源 Java 靜態(tài)代碼分析工具。FindBugs 通過(guò)檢查類文件或 JAR 文件俯逾,將字節(jié)碼與一組缺陷模式進(jìn)行對(duì)比從而發(fā)現(xiàn)代碼缺陷贸桶,完成靜態(tài)代碼分析。FindBugs 既提供可視化 UI 界面纱昧,同時(shí)也可以作為 IntelliJ IDEA插件使用刨啸。文本將主要使用將 FindBugs-IDEA 作為 IntelliJ IDEA插件堡赔。

3.2.2 內(nèi)置編程規(guī)范

Bad practice 壞的實(shí)踐:常見(jiàn)代碼錯(cuò)誤识脆,用于靜態(tài)代碼檢查時(shí)進(jìn)行缺陷模式匹配

Correctness 可能導(dǎo)致錯(cuò)誤的代碼,如空指針引用等

國(guó)際化相關(guān)問(wèn)題:如錯(cuò)誤的字符串轉(zhuǎn)換

可能受到的惡意攻擊善已,如訪問(wèn)權(quán)限修飾符的定義等

多線程的正確性:如多線程編程時(shí)常見(jiàn)的同步灼捂,線程調(diào)度問(wèn)題。

運(yùn)行時(shí)性能問(wèn)題:如由變量定義换团,方法調(diào)用導(dǎo)致的代碼低效問(wèn)題悉稠。

3.2.3 在idea中集成FindBugs

File->Setting->Plugins至下圖界面,搜索FindBugs-IDEA艘包,點(diǎn)擊安裝的猛。

image.png

3.2.4 在idea中使用FindBugs

安裝好重啟耀盗,在IEDA左下角會(huì)有[圖片上傳失敗...(image-9a21eb-1586735691475)]

標(biāo)致的控制面板,點(diǎn)擊面板卦尊,選擇要分析的Java文件點(diǎn)擊[圖片上傳失敗...(image-5d08d-1586735691475)]

分析叛拷,檢查結(jié)果如下。

image.png

插件面板按鈕說(shuō)明

1 分析選中的 Java 文件

2 分析在光標(biāo)所在的類

3 分析選中的包

4 分析選中的模塊 (點(diǎn)擊時(shí)會(huì)詢問(wèn)是否同時(shí)分析 test 包中的類)

5 分析整個(gè)項(xiàng)目 (點(diǎn)擊時(shí)會(huì)詢問(wèn)是否同時(shí)分析 test 包中的類)

6 自定義分析的類

7 分析被修改的類 (搭配 SVN,Git 使用)

8 分析 changelist 中的類 (搭配 SVN,Git 使用)

9 停止分析

10 根據(jù) BUG 類型分組

11 根據(jù)類分組

12 根據(jù)包分組

13 根據(jù) BUG 嚴(yán)重級(jí)別分組

FindBugs 只是一款靜態(tài)代碼分析工具, 雖然分析大多數(shù)的問(wèn)題, 但是如果希望編寫(xiě)更為健壯的程序, 還需進(jìn)行更多的測(cè)試操作, 切不可認(rèn)為 FindBugs 沒(méi)有分析出問(wèn)題便認(rèn)為沒(méi)有問(wèn)題了岂却。

3.3 PMD

3.3.1 簡(jiǎn)介

Facebook 的 Infer 是一個(gè)靜態(tài)分析工具忿薇。Infer 可以分析 Objective-C, Java 或者 C 代碼躏哩,報(bào)告潛在的問(wèn)題署浩。任何人都可以使用 Infer 檢測(cè)應(yīng)用,這可以將那些嚴(yán)重的 bug 扼殺在發(fā)布之前扫尺,同時(shí)防止應(yīng)用崩潰和性能低下筋栋。

3.3.2 內(nèi)置編程規(guī)范

可能的 Bugs:檢查潛在代碼錯(cuò)誤,如空 try/catch/finally/switch 語(yǔ)句

未使用代碼(Dead code):檢查未使用的變量正驻,參數(shù)二汛,方法

復(fù)雜的表達(dá)式:檢查不必要的 if 語(yǔ)句,可被 while 替代的 for 循環(huán)

重復(fù)的代碼:檢查重復(fù)的代碼

循環(huán)體創(chuàng)建新對(duì)象:檢查在循環(huán)體內(nèi)實(shí)例化新對(duì)象

資源關(guān)閉:檢查 Connect拨拓,Result肴颊,Statement 等資源使用之后是否被關(guān)閉掉

3.3.3 在idea中集成PMDPlugin

File->Setting->Plugins至下圖界面,搜索PMDPlugin渣磷,點(diǎn)擊安裝婿着。

image.png

3.3.4 在idea中使用PMDPlugin

在代碼編輯框或Project 窗口的文件夾、包醋界、文件右鍵竟宋,選擇“Run PMD”,“Pre Defined”形纺,“All”丘侠,對(duì)指定的文件夾、包逐样、文件進(jìn)行分析:

image.png

等待一段時(shí)間蜗字,即可看到分析的結(jié)果。

image.png

點(diǎn)擊展開(kāi)即可查看相應(yīng)的具體代碼脂新。

image.png

3.4 Jtest

3.4.1 簡(jiǎn)介

Jtest 是 Parasoft 公司推出的一款針對(duì) Java 語(yǔ)言的自動(dòng)化代碼優(yōu)化和測(cè)試工具挪捕,Jtest 的靜態(tài)代碼分析功能能夠按照其內(nèi)置的超過(guò) 800 條的 Java 編碼規(guī)范自動(dòng)檢查并糾正這些隱蔽且難以修復(fù)的編碼錯(cuò)誤。同時(shí)争便,還支持用戶自定義編碼規(guī)則级零,幫助用戶預(yù)防一些特殊用法的錯(cuò)誤。Jtest 提供了基于Eclipse的插件安裝滞乙。Jtest 支持開(kāi)發(fā)人員對(duì) Java 代碼進(jìn)行編碼規(guī)范檢查奏纪,并在 Jtask 窗口中集中顯示檢查結(jié)果鉴嗤。

3.4.2 內(nèi)置編程規(guī)范

可能的錯(cuò)誤:如內(nèi)存破壞、內(nèi)存泄露序调、指針錯(cuò)誤躬窜、庫(kù)錯(cuò)誤、邏輯錯(cuò)誤和算法錯(cuò)誤等

未使用代碼:檢查未使用的變量炕置,參數(shù)荣挨,方法

初始化錯(cuò)誤:內(nèi)存分配錯(cuò)誤、變量初始化錯(cuò)誤朴摊、變量定義沖突

命名約定:檢查命名是否符合命名規(guī)范

Javadoc 注釋:檢查類及方法的 Javadoc 注釋

線程和同步:檢驗(yàn)多線程編程時(shí)常見(jiàn)的同步默垄,線程調(diào)度問(wèn)題

國(guó)際化問(wèn)題:

垃圾回收:檢查變量及 JDBC 資源是否存在內(nèi)存泄露隱患

3.4.3 在idea中集成Jtest

由于本文是基于IntelliJ IDEA講解的,而Jtest目前沒(méi)有基于IntelliJ IDEA的插件甚纲,因此本部分不作描述(自行搜索參考在Eclipse的使用)口锭。

3.4.4 在idea中使用Jtest

由于本文是基于IntelliJ IDEA講解的,而Jtest目前沒(méi)有基于IntelliJ IDEA的插件介杆,因此本部分不作描述(自行搜索參考在Eclipse的使用)鹃操。

4. 錯(cuò)誤檢查能力

為比較上述 Java 靜態(tài)分析工具的代碼缺陷檢測(cè)能力,本文將使用一段示例代碼進(jìn)行試驗(yàn)春哨,示例代碼中將涵蓋我們開(kāi)發(fā)中的幾類常見(jiàn)錯(cuò)誤荆隘,如引用操作、對(duì)象操作赴背、表達(dá)式復(fù)雜化椰拒、數(shù)組使用、未使用變量或代碼段凰荚、資源回收燃观、方法調(diào)用及代碼設(shè)計(jì)幾個(gè)方面。最后本文將分別記錄在默認(rèn)檢查規(guī)范設(shè)置下便瑟,不同工具對(duì)該示例代碼的分析結(jié)果缆毁。以下為示例代碼 Test.java。其中到涂,代碼的注釋部分列舉了代碼中可能存在的缺陷脊框。

4.1 清單Test.java示例代碼

package Test;

import java.io.*;

public class Test {

    /**

     * Write the bytes from input stream to output stream.

     * The input stream and output stream are not closed.

     * @param is

     * @param os

     * @throws IOException

     */

    public  boolean copy(InputStream is, OutputStream os) throws IOException {

        int count = 0;

        //缺少空指針判斷

        byte[] buffer = new byte[1024];

        while ((count = is.read(buffer)) >= 0) {

            os.write(buffer, 0, count);

        }

        //未關(guān)閉I/O流

        return true;

    }

    /**

     *

     * @param a

     * @param b

     * @param ending

     * @return copy the elements from a to b, and stop when meet element ending

     */

    public void copy(String[] a, String[] b, String ending)

    {

        int index;

        String temp = null;

        //空指針錯(cuò)誤

        System.out.println(temp.length());

        //未使用變量

        int length=a.length;

        for(index=0; index&a.length; index++)

        {

            //多余的if語(yǔ)句

            if(true)

            {

                //對(duì)象比較 應(yīng)使用equals

                if(temp==ending)

                {

                    break;

                }

                //缺少 數(shù)組下標(biāo)越界檢查

                b[index]=temp;

            }

        }

    }

    /**

     *

     * @param file

     * @return file contents as string; null if file does not exist

     */

    public  void  readFile(File file) {

        InputStream is = null;

        OutputStream os = null;

            try {

                is = new BufferedInputStream(new FileInputStream(file));

                os = new ByteArrayOutputStream();

                //未使用方法返回值

                copy(is,os);

                is.close();

                os.close();

            } catch (IOException e) {

                //可能造成I/O流未關(guān)閉

                e.printStackTrace();

            }

            finally

            {

                //空的try/catch/finally塊

            }

    }

}

通過(guò)以上測(cè)試代碼,我們對(duì)已有 Java 靜態(tài)代碼分析工具的檢驗(yàn)結(jié)果做了如下比較养盗。

4.2 Java 靜態(tài)代碼分析工具對(duì)比

image.png

由表中可以看出幾種工具對(duì)于代碼檢查各有側(cè)重缚陷。其中适篙,Checkstyle 更偏重于代碼編寫(xiě)格式往核,及是否符合編碼規(guī)范的檢驗(yàn),對(duì)代碼 bug 的發(fā)現(xiàn)功能較弱嚷节;而 FindBugs聂儒,PMD虎锚,Jtest 著重于發(fā)現(xiàn)代碼缺陷。在對(duì)代碼缺陷檢查中衩婚,這三種工具在針對(duì)的代碼缺陷類別也各有不同窜护,且類別之間有重疊。

5.結(jié)論

本文分別從功能非春、特性和內(nèi)置編程規(guī)范等方面詳細(xì)介紹了包括 Checkstyle柱徙,F(xiàn)indBugs,PMD奇昙,Jtest 在內(nèi)的四種主流 Java 靜態(tài)代碼分析工具护侮,并通過(guò)一段 Java 代碼示例對(duì)這四種工具的代碼分析能力進(jìn)行比較。由于這四種工具內(nèi)置編程規(guī)范各有不同储耐,因此它們對(duì)不同種類的代碼問(wèn)題的發(fā)現(xiàn)能力也有所不同羊初。其中 Checkstyle 更加偏重于代碼編寫(xiě)格式檢查,而 FindBugs什湘,PMD长赞,Jtest 著重于發(fā)現(xiàn)代碼缺陷。最后闽撤,希望本文能夠幫助 Java 軟件開(kāi)發(fā)和測(cè)試人員進(jìn)一步了解以上五種主流 Java 靜態(tài)分析工具得哆,并幫助他們根據(jù)需求選擇合適的工具。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哟旗,一起剝皮案震驚了整個(gè)濱河市柳恐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌热幔,老刑警劉巖乐设,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異绎巨,居然都是意外死亡近尚,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)场勤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)戈锻,“玉大人,你說(shuō)我怎么就攤上這事和媳「裨猓” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵留瞳,是天一觀的道長(zhǎng)拒迅。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么璧微? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任作箍,我火速辦了婚禮,結(jié)果婚禮上前硫,老公的妹妹穿的比我還像新娘胞得。我一直安慰自己,他們只是感情好屹电,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布阶剑。 她就那樣靜靜地躺著,像睡著了一般危号。 火紅的嫁衣襯著肌膚如雪个扰。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,598評(píng)論 1 305
  • 那天葱色,我揣著相機(jī)與錄音递宅,去河邊找鬼。 笑死苍狰,一個(gè)胖子當(dāng)著我的面吹牛办龄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播淋昭,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼俐填,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了翔忽?” 一聲冷哼從身側(cè)響起英融,我...
    開(kāi)封第一講書(shū)人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎歇式,沒(méi)想到半個(gè)月后驶悟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡材失,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年痕鳍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片龙巨。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡笼呆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出旨别,到底是詐尸還是另有隱情诗赌,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布秸弛,位于F島的核電站铭若,受9級(jí)特大地震影響洪碳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜奥喻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一偶宫、第九天 我趴在偏房一處隱蔽的房頂上張望非迹。 院中可真熱鬧环鲤,春花似錦、人聲如沸憎兽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)纯命。三九已至西剥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間亿汞,已是汗流浹背瞭空。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疗我,地道東北人咆畏。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像吴裤,于是被迫代替她去往敵國(guó)和親旧找。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355