一、编码格式规范(CheckStyle)
a、安装checkstyle 的Eclipse插件1.下载地址:http://pan.baidu.com/s/1o6LOSwM2.解压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.html2.解压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\\pmd4.关闭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、使用PMD1.右键单击源文件夹并选择 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\\coverlipse5.关闭Eclipse,重启。然后在Eclipse的window》Preferences下就可以看到PMD菜单,安装成功,如下图(需要junit测试)
b、使用PMD1.右击项目,选择如下选项
2.可以对PCD生成的重复代码进行分析,修改
五、findbugs
1.下载地址:
http://downloads.sourceforge.net/project/findbugs/findbugs eclipse plugin/1.3.9/edu.umd.cs.findbugs.plugin.eclipse_1.3.9.20090821.zip?use_mirror=ncu
2.把下载的压缩包解压后,将其copy到eclipse的plugin目录中去。