Java代码质量检查工具

本文详细介绍了如何在Eclipse中安装和使用Java代码质量检查工具CheckStyle、PMD和jdepend,以及代码覆盖率工具Coverlipse,并提供了下载链接和配置步骤。通过这些工具,可以有效地提升代码质量和分析代码依赖性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、编码格式规范(CheckStyle)

a、安装checkstyle 的Eclipse插件
1.下载地址:http://pan.baidu.com/s/1o6LOSwM
2.解压net.sf.eclipsecs-updatesite_5.6.1.201306282206-bin.zip文件,到系统路径下。如:D:\eclipse-plugins\cs(注:一定不用起名为checkstyle,不知道为什么此名就是安装不成功),此文件夹下有两个文件夹features、plugins。
3.我们使用link的方式安装。在Eclipse的dropins文件夹下新建checkstyle.link文件,内容为:path=D:\\eclipse-plugins\\cs
关闭Eclipse,重启。然后在Eclipse的window》Preferences下就可以看到checkstyle菜单,安装成功,如下图


b、使用checkstyle

导入CheckStyle规则my_checkStyle.xml,eclipse——Windows——preferences



2.右击项目,选择preferences


3.右击项目选择如下选择


4.经CheckStyle检查过的代码如下


c、相关文档
1.源代码https://github.com/checkstyle/checkstyle

2.文档http://checkstyle.sourceforge.net

例.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">

<module name="Checker">
    <property name="severity" value="warning"/>
	
    <!-- 文件长度不超过1500行 -->
    <module name="FileLength">
        <property name="max" value="1500"/>
		<message key="maxLen.file" value="文件长度不超过1500行。"/>
    </module>	
	
    <module name="TreeWalker">
		<!-- 
			(1)module节点,指检查项,如MethodName (检查方法命名)
				module中有两个比较重要的节点,它们分别是Checker(checkStyle配置文件的根节点,必须存在)、TreeWalker(树遍历器),TreeWalker会自动去检查指定范围内的每一个java源文件,TreeWalker内部会定义很多module。
				
			(2)property节点
				对应module 检查项中具体检查属性,如果使用默认值,property节点可以省略;
				
			(3)message节点
				checkStyle检查出来,是否打印出message消息,message节点可以省略
		-->
	<!--java.lang.Deprecated注解或@deprecated的Javadoc标记不能同时存在-->
	<module name="MissingDeprecated"/>
	<!--出现{@inheritDoc}的Javadoc标签时,java.lang.Override注解不能出现。-->
	<module name="MissingOverride"/>
	<!--除了程序真正的入口点之外,源码中其他所有的main()方法都应当被删除或注释掉。-->
	<module name="UncommentedMain"/>
	<!--代码中含有注释的行中只包含注释。不建议行尾注释-->
	<module name="TrailingComment"/>
		
	<!-- import检查-->
	<!-- 检查是否从非法的包中导入了类 -->
        <module name="IllegalImport"/>
		
	<!-- 检查是否导入了多余的包 -->
        <module name="RedundantImport"/>
		
	<!-- 没用的import检查,比如:1.没有被用到2.重复的3.import java.lang的4.import 与该类在同一个package的 -->
	<module name="UnusedImports">
		<message key="import.unused" value="没用的import."/>
	</module>
		
		
	<!-- Javadoc注释检查 -->
        <!-- 检查构造函数的javadoc -->
	<!--<module name="JavadocType">
            <property name="allowUnknownTags" value="true"/>
            <message key="javadoc.missing" value="类注释:缺少Javadoc注释。"/>
        </module>-->
		
		
	<!-- 命名检查 Naming -->
	<!-- 抽象类名称 -->
	<module name="AbstractClassName">
		<message key="illegal.abstract.class.name" value="抽象类名称 ''{0}'' 要匹配''{1}''的格式."/>
	</module>
        <!-- 局部的final变量,包括catch中的参数的检查 -->
	<module name="LocalFinalVariableName">
		<message key="name.invalidPattern" value="局部final变量 ''{0}'' 要匹配''{1}''的格式(建议除首单词外的单词的首字母大写)."/>
	</module>
		
	<!-- 局部的非final型的变量,包括catch中的参数的检查 -->
        <module name="LocalVariableName">
		<property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
		<message key="name.invalidPattern" value="局部的非final型的变量 ''{0}'' 要匹配''{1}''的格式(建议除首单词外的单词的首字母大写)."/>
	</module>
		
	<!-- 仅仅是static型的变量(不包括static final型)的检查 -->
	<module name="StaticVariableName">
		<message key="name.invalidPattern" value="静态非final变量 ''{0}'' 要匹配''{1}''的格式(建议除首单词外的单词的首字母大写)."/>
	</module>
		
	<module name="TypeName">
		<property name="format" value="^[A-Z][a-zA-Z0-9_]*$"/>
		<message key="name.invalidPattern" value="名字 ''{0}'' 要符合 ''{1}''的格式(建议每个单词的首字母大写)."/>
	</module>
		
	<module name="PackageName">
		<property name="format" value="^[a-z]+(\.[a-z_][a-z0-9_]*)*$"/>
		<message key="name.invalidPattern" value="包名 ''{0}''要匹配 ''{1}''的格式(所有字母全部小写)."/>
	</module>
		
	<!-- 非static型变量的检查 -->
	<module name="MemberName">
		<message key="name.invalidPattern" value="非static型变量 ''{0}'' 要匹配''{1}''的格式(建议除首单词外的单词的首字母小写)."/>
	</module>
		
	<module name="ConstantName">
		<message key="name.invalidPattern" value="常量 ''{0}'' 要匹配''{1}''的格式(字母全部大写可以包含_)."/>
	</module>
		
	<module name="MethodName">
		<property name="format" value="^[a-z][a-zA-Z]*$"/>
		<message key="name.invalidPattern" value="方法名 ''{0}'' 必须要满足 ''{1}''的格式,建议除首单词外每个单词的首字母大写."/>
		<message key="method.name.equals.class.name" value="方法名 ''{0}'' 不能等于类名."/>
	</module>
		
	<module name="ParameterName">
		<property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
		<message key="name.invalidPattern" value="方法的参数名 ''{0}''要匹配''{1}''的格式,建议除首单词外的每个单词的首字母大写."/>
	</module>
		
		
	<!-- 定义检查 -->
        <!-- 检查数组类型定义的样式 -->
	<module name="ArrayTypeStyle">
		<message key="array.type.style" value="数组定义要采取String [] args这种方式。"/>
	</module>
		
	<module name="UpperEll">
		<message key="upperEll" value="应该使用大写的 ''L''."/>
	</module>
		
		
	<!-- Size长度检查 -->
        <!-- 每行不超过140个字符 -->
	<module name="MethodLength">
		<property name="max" value="150"/>
		<message key="maxLen.method" value="方法大小不可以超过150行。"/>
	</module>
		
	<module name="LineLength">
		<property name="max" value="140" />
		<message key="maxLineLen" value="每一行的最大长度为140个字符。"/>
	</module>
		
	<!-- 方法的参数个数不超过5个。 并且不对构造方法进行检查-->
        <module name="ParameterNumber">
            <property name="max" value="5" />
            <property name="tokens" value="METHOD_DEF" />
		<message key="maxParam" value="方法参数个数不能超过5个。"/>
        </module>
		
		
	<!-- Whitespace空格检查-->
	<module name="GenericWhitespace"/>
	<!-- 方法名后跟左圆括号"(" -->
	<module name="MethodParamPad">
		<property name="tokens" value="CTOR_DEF,METHOD_CALL,METHOD_DEF,SUPER_CTOR_CALL"/>
		<message key="ws.notPreceded" value="''{0}'' 前面保留一个空格"/>
		<message key="line.previous" value="''{0}'' 必须在前一行"/>
		<message key="ws.preceded" value="''{0}'' 前面有一个空格"/>
	</module>
	<!-- 在类型转换时,不允许左圆括号右边有空格,也不允许与右圆括号左边有空格 -->
	<module name="TypecastParenPad">
		<property name="tokens" value="RPAREN,TYPECAST"/>
		<message key="ws.followed" value="''{0}''后面有一个空格,请删除."/>
		<message key="ws.preceded" value="''{0}''前面有一个空格,请删除."/>
	</module>
	<!-- 检查在某个特定关键字之后应保留空格 -->
        <module name="NoWhitespaceAfter">
		<message key="ws.followed" value="在某个特定关键字之后应保留空格."/>
	</module>
	<!-- 检查在某个特定关键字之前应保留空格 -->
        <module name="NoWhitespaceBefore">
		<message key="ws.preceded" value="在某个特定关键字之前应保留空格."/>
	</module>
	<!-- 操作符换行策略检查 -->
        <module name="OperatorWrap">
		<property name="option" value="nl"/>
		<message key="line.new" value="操作符换行策略检查."/>
	</module>
	<!-- 圆括号空白 -->
        <module name="ParenPad"/>
	<!-- 检查分隔符是否在空白之后 -->
        <module name="WhitespaceAfter">
		<message key="ws.notFollowed" value="分隔符在空白之后."/>
		<message key="ws.typeCast" value="分隔符在空白之后."/>
	</module>
	<!-- 检查分隔符周围是否有空白 -->
        <module name="WhitespaceAround">
		<message key="ws.notPreceded" value="分隔符周围需要有空白."/>
		<message key="ws.notFollowed" value="分隔符周围需要有空白."/>
	</module>
		
	<!-- Modifiers修饰符检查 -->
        <!-- 检查修饰符的顺序是否遵照java语言规范,默认public、protected、private、abstract、static、final、transient、volatile、synchronized、native、strictfp -->
        <module name="ModifierOrder"/>
		
        <!-- 检查接口和annotation中是否有多余修饰符,如接口方法不必使用public -->
        <module name="RedundantModifier"/>
		
		
	<!-- Blocks代码块检查 -->
	<!-- 检查是否有嵌套代码块 -->
	<module name="AvoidNestedBlocks">
		<!--<property name="allowInSwitchCase" value="true"/>-->
		<message key="block.nested" value="语句中有嵌套的代码块"/>
	</module>
		
	<!-- 检查是否有空代码块 -->
	<module name="EmptyBlock">
		<message key="block.empty" value="{0}空的代码块."/>
		<message key="block.noStmt" value="至少有一条代码语句."/>
	</module>
		
	<!-- 检查左大括号位置 -->
        <module name="LeftCurly"/>
		
	<!-- 检查代码块是否缺失{} -->
	<module name="NeedBraces">
		<message key="needBraces" value="代码中缺失大括号"/>
	</module>
		
	<!-- 检查右大括号位置 -->
        <module name="RightCurly"/>
		
		
	<!-- Coding 代码检查 -->
	<!-- 检查空的代码段 -->
	<module name="EmptyStatement">
		<message key="empty.statement" value=";前面缺失语句"/>
	</module>
		
	<!-- 检查在重写了equals方法后是否重写了hashCode方法 -->
        <module name="EqualsHashCode"/>
		
	<!-- 检查局部变量或参数是否隐藏了类中的变量 -->
        <module name="HiddenField">
            <property name="tokens" value="VARIABLE_DEF"/>
        </module>
		
	<!-- 检查子表达式中是否有赋值操作 -->
        <module name="InnerAssignment"/>
		
	<!-- 检查switch语句是否有default -->
        <module name="MissingSwitchDefault"/>
		
	<!-- 检查是否有过度复杂的布尔表达式 -->
        <module name="SimplifyBooleanExpression"/>
		
        <!-- 检查是否有过于复杂的布尔返回代码段 -->
        <module name="SimplifyBooleanReturn"/>
		
		
	<!-- Design类设计检查 -->
	<!-- 检查类是否为扩展设计l -->
        <!-- 检查只有private构造函数的类是否声明为final -->
        <module name="FinalClass"/>
		
	<!-- 检查接口是否仅定义类型 -->
        <module name="InterfaceIsType"/>
		
	<!-- 检查类成员的可见度 检查类成员的可见性。只有static final 成员是public的 
        除非在本检查的protectedAllowed和packagedAllowed属性中进行了设置-->
        <module name="VisibilityModifier">
            <property name="packageAllowed" value="true"/>
            <property name="protectedAllowed" value="true"/>
        </module>
		
		
	<!--<module name="Indentation">
		<message key="indentation.child.error" value="你缩进了{1}个空格,正确应该缩进 {2}个空格。"/>
		<message key="indentation.error" value="你缩进了{1}个空格,正确应该缩进 {2}个空格。"/>
	</module>-->

	<module name="RedundantThrows">
		<property name="suppressLoadErrors" value="true"/>
		<message key="redundant.throws.subclass" value="Redundant throws: ''{0}'' 是''{1}''的异常子类."/>
		<message key="redundant.throws.classInfo" value="无法从 {0}获取类信息."/>
		<message key="redundant.throws.duplicate" value="Redundant throws: ''{0}'' 重复抛出异常."/>
		<message key="redundant.throws.unchecked" value="Redundant throws: ''{0}'' 没有检查异常."/>
	</module>
	<!-- String的比较不能用!= 和 == -->
	<module name="StringLiteralEquality" > 
		<message key="string.literal.equality" value="String的比较不能用!= 和 ==."/>
	</module>
	<!-- if最多嵌套3层 -->  
	<module name="NestedIfDepth">   
		<property name="max" value="3" />   
		<message key="nested.if.depth" value="if最多嵌套3层"/>
	</module>
		<!-- try最多被嵌套3层 -->   
        <module name="NestedTryDepth">   
                <property name="max" value="3" /> 
		<message key="nested.if.depth" value="try最多被嵌套3层"/>
        </module> 
	<!-- 限制for循环最多嵌套2层 -->
        <!--<module name="NestedForDepth">
            <property name="max" value="2"/>
        </module>-->
        <!-- clone方法必须调用了super.clone() -->   
	<module name="SuperClone" />
	<!-- finalize 必须调用了super.finalize() -->   
        <module name="SuperFinalize" /> 

	<!-- 确保一个类有package声明 -->   
	<module name="PackageDeclaration" /> 
        <!-- 一个方法中最多有2个return -->   
	<module name="ReturnCount">   
        <property name="max" value="2" /> 
		<message key="return.count" value="一个方法中最多有2个return"/>
        </module> 
	<!--声明顺序检查-->
	<!--<module name="DeclarationOrder" /> -->
	<!--多重变量声明-->
	<module name="MultipleVariableDeclarations">
		<message key="multiple.variable.declarations.comma" value="每一行申请一个变量"/>
		<message key="multiple.variable.declarations" value="每一行允许定义一个变量"/>
	</module>
	<!--检查代码中是否使用了不必要的圆括号-->
	<module name="UnnecessaryParentheses">
		<message key="unnecessary.paren.assign" value="任务的右边含有不必要的圆括号"/>
		<message key="unnecessary.paren.string" value="字符串 {0}含有不必要的圆括号."/>
		<message key="unnecessary.paren.literal" value="''{0}''含有不必要的圆括号."/>
		<message key="unnecessary.paren.ident" value="标识符''{0}''含有不必要的圆括号."/>
		<message key="unnecessary.paren.return" value="return 值里含有不必要的圆括号"/>
		<message key="unnecessary.paren.expr" value="表达式里含有不必要的圆括号"/>
		<message key="unnecessary.paren.lambda" value="含有不必要的圆括号"/>
	</module>
		
	<module name="Regexp">
            <property name="format" value="System\.out\.println"/>
            <property name="illegalPattern" value="true"/>
        </module>
		
	<!--<module name="FinalParameters">
		<property name="severity" value="warning"/>
		<property name="tokens" value="CTOR_DEF"/>
		<message key="final.parameter" value="构造器的参数需要是final的"/>
        </module>-->
		
	<module name="BooleanExpressionComplexity">
		<property name="severity" value="warning"/>
	</module>
		
	<module name="InnerTypeLast">
		<property name="severity" value="warning"/>
		<message key="arrangement.members.before.inner" value="最后声明内部类型"/>
	</module>
	<!--switch语句中的default在所有的case分支之后-->
	<module name="DefaultComesLast"/>
	<!--代码中不能有空语句(也就是单独的;符号)-->
	<module name="EmptyStatement"/>
	<!--equals()比较方法中,任意组合的String常量是否位于左边-->
	<module name="EqualsAvoidNull"/>
	<!--在重写了equals方法后不能再重写了hashCode方法-->
	<module name="EqualsHashCode"/>
	<!--类或对象的成员需要显式地初始化为成员所属类型的默认值-->
	<module name="ExplicitInitialization"/>
	<!--从未改变取值的局部变量需要被声明为final-->
	<!--<module name="FinalLocalVariable"/>-->
	<!-- 检查是否使用工厂方法实例化 -->
        <module name="IllegalInstantiation"/>
	<!--<module name="IllegalCatch"/>
	<module name="IllegalThrows"/>
	<module name="InnerAssignment"/>-->
	<!-- 检查是否有"魔术"数字 -->
        <module name="MagicNumber">
            <property name="ignoreNumbers" value="0, 1"/>
            <property name="ignoreAnnotation" value="true"/>
	    <message key="magic.number" value="有魔术数字"/>
	</module>
	<!-- switch语句是否含有default子句。 -->
	<module name="MissingSwitchDefault"/>
	<!-- 确保for循环的控制变量没有在for代码块中被修改。否则用while循环代替 -->
	<module name="ModifiedControlVariable"/>
	<!-- 在单个文件中,相同的字符串常量不可出现多次。 -->
	<!--<module name="MultipleStringLiterals"/>-->
	<!-- 不允许对参数进行赋值。 -->
	<module name="ParameterAssignment"/>
	<!-- 引用当前对象的实例变量和方法时,应当显式地通过“this.varName”或“this.methodName(args)”这种形式进行调用 -->
	<!--<module name="RequireThis">
		<property name="checkMethods" value="false"/>
	</module>-->
	<!-- 不可使用过于复杂的布尔表达式-->
	<module name="SimplifyBooleanExpression"/>
	<!-- 不可使用过于复杂的布尔类型return语句-->
	<module name="SimplifyBooleanReturn"/>
	<!-- 每行一条语句-->
	<module name="OneStatementPerLine"/>
		
	<!-- 避免使用* -->
        <module name="AvoidStarImport">
            <property name="excludes" value="java.io,java.net,java.lang.Math"/>
            <!-- 实例;import java.util.*;.-->
            <property name="allowClassImports" value="false"/>
            <!-- 实例 ;import static org.junit.Assert.*;-->
            <property name="allowStaticMemberImports" value="true"/>
            </module>
		
            <module name="OuterTypeNumber">
		<property name="max" value="2"/>
	    </module>
	</module>
</module>

二、代码重复检查(PMD)

a、安装PMD 的Eclipse插件
1.下载地址:http://jingyan.baidu.com/article/19192ad835de6ee53e57073c.html
2.解压net.sourceforge.pmd.eclipse-3.2.6.v200903300643.zip文件,到系统路径下。如:D:\eclipse-plugins\pmd,此文件夹下有两个文件夹features、plugins。
3. 我们使用link的方式安装。在Eclipse的dropins文件夹下新建pmd.link文件,内容为:path=D:\\eclipse-plugins\\pmd
4.关闭Eclipse,重启。然后在Eclipse的window》Preferences下就可以看到PMD菜单,安装成功,如下图


b、使用PMD

1.右击项目,选择如下选项



2.下面是PCD生成的重复代码,可以对其中的代码进行分析,修改


三、依赖项分析(jdepend)

a、安装jdepend 的Eclipse插件

1.下载地址:http://andrei.gmxhome.de/jdepend4eclipse/links.html


2.拷贝de.loskutov.eclipse.jdepend_1.2.4.201406241900.jar文件,到Eclipse的dropins目录下。

3. 关闭Eclipse,重启。通过右键单击源文件夹并选择 Run JDepend Analysis。一定要选择一个含源代码的源文件夹;否则看不到此菜单项。


b、使用PMD

1.右键单击源文件夹并选择 Run JDepend Analysis


2.下面对jdepend的分析的结果简单介绍:
A.Selected objects():选择分析的包
B.Package:包全路径
C.CC(concr.cl.):当前行对应包的具体类的数量。
D.AC(abstr.cl.):当前行对应包的抽象类和接口的数量。
E.Ca(aff.):依赖于被分析package的其他package的数量,用于衡量pacakge的职责。即有多少包调用了它。(AfferentCouplings)
F.Ce(eff.):被分析package的类所依赖的其他package的数量,用于衡量package的独立性。即它调用了多少其他包。(EfferentCouplings)
G.A:被分析package中的抽象类和接口与所在package所有类数量的比例,取值范围为0-1。(Abstractness )
H.I:I=Ce/(Ce+Ca),用于衡量package的不稳定性,取值范围为0-1。I=0表示最稳定,I=1表示最不稳定。即如果这个类不调用任何其他包,则它是最稳定的。(Instability )
I.D:分析package和理想曲线A+I=1的垂直距离,用于衡量package在稳定性和抽象性之间的平衡。(Distance)
理想的package要么完全是抽象类和稳定(x=0,y=1),要么完全是具体类和不稳定(x=1,y=0)。取值范围为0-1,
D=0表示完全符合理想标准,
D=1表示package最大程度地偏离了理想标准。即你的包要么全是接口,不调用任何其他包(完全是抽象类和稳定),要么是具体类,不被任何其他包调用。
J.Cycle!:循环依赖
K.Package with cycle:包与包直接有循环调用
L.Depends upon-efferentdependencies:依赖的包
M.Used by-afferentdependencies:被引用的包

如果三个包中的类有传递依赖,Cycle!列中会出现感叹号警告。把其中的某个或者某些类再单独抽出新包,解决此问题。

四、代码覆盖率Coverlipse

a、安装coverlipse 的Eclipse插件
1.下载地址:https://sourceforge.net/projects/coverlipse/files/Coverlipse/

2.下载下图中5个文件


3.解压coverlipse-0.9.6.zip文件,到系统路径下。如:D:\eclipse-plugins\ 。
4. 我们使用link的方式安装。在Eclipse的dropins文件夹下新建coverlipse.link文件,内容为:path=D:\\eclipse-plugins\\coverlipse

5.关闭Eclipse,重启。然后在Eclipse的window》Preferences下就可以看到PMD菜单,安装成功,如下图(需要junit测试)



b、使用PMD

1.右击项目,选择如下选项



2.可以对PCD生成的重复代码进行分析,修改

五、findbugs

1.下载地址:

http://downloads.sourceforge.net/project/findbugs/findbugs%20eclipse%20plugin/1.3.9/edu.umd.cs.findbugs.plugin.eclipse_1.3.9.20090821.zip?use_mirror=ncu

2.把下载的压缩包解压后,将其copy到eclipse的plugin目录中去。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值