一、编码格式规范(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
3. 关闭Eclipse,重启。通过右键单击源文件夹并选择 Run JDepend Analysis。一定要选择一个含源代码的源文件夹;否则看不到此菜单项。
1.右键单击源文件夹并选择 Run JDepend Analysis
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个文件
4. 我们使用link的方式安装。在Eclipse的dropins文件夹下新建coverlipse.link文件,内容为:path=D:\\eclipse-plugins\\coverlipse
5.关闭Eclipse,重启。然后在Eclipse的window》Preferences下就可以看到PMD菜单,安装成功,如下图(需要junit测试)
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目录中去。