checkStyle简介
Checksytle 是一款代码格式检查工具。它可以根据设置好的编码规则来检查代码。
比如符合规范的变量命名,良好的程序风格等等。
如果你的项目经理开会时说,“我希望我们写出来的代码就象一个人写的!” 时,用Checkstyle绝对是正确选择,checkStyle主要用于以下三个方面。
1 ant : 编写脚本,调用checkstyle。一般用于构建脚本的一部分。
2 eclipse:作为插件调用checkstyle。一般用于开发人员自行检查。
3 cvs :需要编写perl脚本调用checkstyle。提交代码到cvs时触发checkstyle检查,如果不符合要求则无法提交。
以下只讲述eclipse:作为插件调用checkstyle用于开发人员自行检查。
2.checkStyle在myeclipse 8.6中的安装
一、下载到checkStyle4.4.1安装包并解压,
把com.atlassw.tools.eclipse.checkstyle_4.4.1-bin里面的两个文件夹features和plugins里面的文件夹考到MyEclipse8.6安装目录
比如:D:\Program Files\Genuitec\Common里面对应的两个文件夹下
说明:plugins可以有多个文件夹,不管有多少个都考进去
二、修改
D:\ProgramFiles\Genuitec\MyEclipse-8.6\configuration\org.eclipse.equinox.simpleconfigurator文件夹下的bundles.info文件,
在最后加上两行配置:
com.atlassw.tools.eclipse.checkstyle,4.4.1,file:/D:/Program Files/Genuitec/Common/
plugins/com.atlassw.tools.eclipse.checkstyle_4.4.1/,4,false
net.sf.eclipsecs.stats,1.0.4,file:/D:/Program Files/Genuitec/Common/plugins/net.sf.eclipsecs.stats_1.0.4/,4,false
配置大概的格式是:文件名,版本,路径,4,false(具体的我也没查是什么意思)
三、重启MyEclipse
<!--[endif]-->
checkStyle插件安装成功.
3.checkStyle自定义规则的制定
一,默认规则
checkSyle默认的情况下使用的是sun_checks.xml文件的自定的规则,假如用这个文件自定的规则对代码进行检查会发现成千上万的错误。
二,自定义规则
写一个自定义文件
<!--[endif]-->
在myeclipse中设置关联上自定义文件,并且设置为默认的检测配置文件。
<!--[endif]-->
三.自定义规则的写法及含义。
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.2//EN"
"http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
<module name="Checker">
<!-- 重复代码的检查,超过8行就认为重复,UTF-8格式
本检查一定要放在"TreeWalker"节点前,否则在
Checkclipse中会无法使用。(在ant下可以)
-->
<module name="StrictDuplicateCode">
<property name="min" value="8"/>
<property name="charset" value="UTF-8"/>
</module>
<module name="TreeWalker">
<!-- javadoc的检查 -->
<!-- 检查所有的interface和class
<module name="JavadocType"/> -->
<!-- 检查所有方法的javadoc,可以不声明RuntimeException
<module name="JavadocMethod">
<property name="allowUndeclaredRTE" value="true"/>
</module> -->
<!-- 检查某个变量的javadoc
<module name="JavadocVariable"/> -->
<!-- 命名方面的检查,它们都使用了Sun官方定的规则。 -->
<!-- 类名(class 或interface) 的检查 -->
<module name="TypeName"/>
<!-- 变量的检查 -->
<module name="MemberName"/>
<!-- 方法名的检查 -->
<module name="MethodName"/>
<!-- 方法的参数名 -->
<module name="ParameterName "/>
<!-- 常量名的检查 -->
<module name="ConstantName"/>
<!-- 长度方面的检查 -->
<!-- 文件长度不超过1500行 -->
<module name="FileLength">
<property name="max" value="1500"/>
</module>
<!-- 每行不超过120个字-->
<module name="LineLength">
<property name="max" value="120"/>
</module>
<!-- 方法不超过30行 -->
<module name="MethodLength">
<property name="tokens" value="METHOD_DEF"/>
<property name="max" value="300"/>
</module>
<!-- 方法的参数个数不超过3个。 -->
<module name="ParameterNumber">
<property name="max" value="3"/>
</module>
<!-- 多余的关键字 -->
<module name="RedundantModifier"/>
<!-- 对区域的检查 -->
<!-- 不能出现空白区域 -->
<module name="EmptyBlock"/>
<!-- 所有区域都要使用大括号。 -->
<module name="NeedBraces"/>
<!-- 多余的括号 -->
<module name="AvoidNestedBlocks">
<property name= "allowInSwitchCase"
value="true"/>
</module>
<!-- 编码方面的检查 -->
<!-- 不许出现空语句 -->
<module name="EmptyStatement"/>
<!-- 每个类都实现了equals()和hashCode() -->
<module name="EqualsHashCode"/>
<!-- 不许使用switch -->
<module name="IllegalToken">
<property name="tokens"
value="LITERAL_SWITCH"/>
</module>
<!-- 不许内部赋值 -->
<module name="InnerAssignment"/>
<!-- 绝对不能容忍魔法数 -->
<module name="MagicNumber">
<property name="tokens" value="NUM_DOUBLE"/>
</module>
<!-- 循环控制变量不能被修改 -->
<module name="ModifiedControlVariable"/>
<!-- 多余的throw -->
<module name="RedundantThrows"/>
<!-- 不许使用未被简化的条件表达式 -->
<module name="SimplifyBooleanExpression"/>
<!-- 不许使用未被简化的布尔返回值 -->
<module name="SimplifyBooleanReturn"/>
<!-- String的比较不能用!= 和 == -->
<module name="StringLiteralEquality"/>
<!-- if最多嵌套3层 -->
<module name="NestedIfDepth">
<property name="max" value="3"/>
</module>
<!-- try最多被嵌套1层 -->
<module name="NestedTryDepth"/>
<!-- clone方法必须调用了super.clone() -->
<module name="SuperClone"/>
<!-- finalize 必须调用了super.finalize() -->
<module name="SuperFinalize"/>
<!-- 不能catch java.lang.Exception -->
<module name="IllegalCatch">
<property name="illegalClassNames"
value="java.lang.Exception"/>
</module>
<!-- JUnitTestCase 的核心方法存在。 -->
<module name="JUnitTestCase"/>
<!-- 一个方法中最多有3个return -->
<module name="ReturnCount">
<property name="max" value="3"/>
</module>
<!-- 不许对方法的参数赋值 -->
<module name="ParameterAssignment"/>
<!-- 不许有同样内容的String -->
<module name="MultipleStringLiterals"/>
<!-- 同一行不能有多个声明 -->
<module name="MultipleVariableDeclarations"/>
<!-- 各种量度 -->
<!-- 布尔表达式的复杂度,不超过3 -->
<module name="BooleanExpressionComplexity"/>
<!-- 类数据的抽象耦合,不超过7 -->
<module name="ClassDataAbstractionCoupling"/>
<!-- 类的分散复杂度,不超过20 -->
<module name="ClassFanOutComplexity"/>
<!-- 函数的分支复杂度,不超过10 -->
<module name="CyclomaticComplexity"/>
<!-- NPath复杂度,不超过200 -->
<module name="NPathComplexity"/>
<!-- 杂项 -->
<!-- 禁止使用System.out.println -->
<module name="GenericIllegalRegexp">
<property name="format" value="System\.out\.println"/>
<property name="ignoreComments" value="true"/>
</module>
<!-- 不许使用与代码同行的注释 -->
<module name="TrailingComment"/>
</module>
<!-- 检查翻译文件 -->
<module name="Translation"/>
</module>
四,对部分自定义规则的解释
a.重复的代码
本检查应该放在<module name = "Checker">结点下。重复代码的检查可以让你找到经过COPY/PAST出来的代码。
重复代码的典型缺点是增加维护代价, 因为需要你把一个BUG修改很多次,测试更多次。
当代码只是在缩进上有所不同时,就把它们逐行的进行比较,并报告是否重复。
忽略import , 其他的内容,包括javadoc, 方法间隔的空白行,等都会被包含进来,进行比较。
使用默认检查:
<module name="StrictDuplicateCode"/>
相同代码行超过15行,并且文件编码是UTF-8的检查:
<module name="StrictDuplicateCode">
<property name="min" value="15"/>
<property name="charset" value="UTF-8"/>
</module>
本检查会把空白行算在检查范围里。如果代码中存在一段多于"min"属性所定义的空白行时,也会报错。
例如,"min"=8 时, 如果代码中存在9个连续的空白行,就会报错。
b.各种量度
编码时的各种量度,很理论化。我还没在国内的其他文档中看到此类内容,所以把内容基本照搬来了,大家共同学习吧。
(1).布尔表达式的复杂度
限制一个布尔表达式中的 &&, || 和^的个数。可以让代码看起来更清晰,容易排错和维护。默认检查:
<module name="BooleanExpressionComplexity"/>
最多允许7个操作符:
<module name="BooleanExpressionComplexity">
<property name="max" value="7"/>
</module>
其中的"max"指定了允许的操作符的最大数,默认是3。
(2).类数据的抽象耦合
ClassDataAbstractionCoupling
检查一个类中建立的其他类的实例的个数。这种类型的耦合不是由继承或面向对象的聚合而引起的。
一般而言,任何一个抽象数据类型,如果将其他抽象数据类型作为自己的成员,那么它都会产生数据抽象耦合(DAC);
换句话说,如果一个类使用了其他类的实例作为自己的成员变量,那么就会产生数据抽象耦合。
耦合度越高,这个系统的数据结构就越复杂。
申思维注:也就是说,一个类中如果使用太多其他的类,是肯定会增加系统复杂度的。使用其他的类越少,耦合度就越少。
耦合度最多是5的检查:
<module name="ClassDataAbstractionCoupling">
<property name="max" value="5"/>
</module>
其中"max"属性指定了最大数,默认是7。
(3).类的分散复杂度
ClassFanOutComplexity
一个类依靠的其他类的个数。这个数字的平方也会被显示出来,以表示最少需要的修改个数。分散复杂度最多是10:
<module name="ClassFanOutComplexity">
<property name="max" value="10"/>
</module>
其中"max"属性指定了最大数,默认是20。
(4).函数的分支复杂度
CyclomaticComplexity
确保函数的分支复杂度没有超出限制。
该复杂度是通过考察大部分函数(构造函数,一般方法,静态初始函数,实例初始化函数)
中的 if, while, do, for, ? : , catch, switch, case 语句 和 &&, || 的操作符的数目来计算得到的。
它表示了通过一个函数的最少分支数,也因此体现了需要进行的测试数目。
一般而言1-4 是优秀,5-7是合格。8-10看情况重构。11个以上一定要马上重构!
分支复杂度最多是7的检查:
<module name="CyclomaticComplexity">
<property name="max" value="7"/>
</module>
其中"max"属性指定了最大数,默认是10。
(5).Npath复杂度
NpathComplexity
NPATH 量度 计算了一个函数的可执行的分支个数。它很重视条件语句的嵌套和多个部分组成的布尔表达式 (比如, A&&B, C||D, 等等)。
Nejmeh说,他的小组有一个非正式的NPATH约定:不超过200。NPATH超过这个数字的函数就一定要被分解。
复杂度不超过40:
<module name="NPathComplexity">
<property name="max" value="40"/>
</module>
其中"max"属性指定了最大数,默认是200。
c.杂项
很难归类的杂项
(1).禁止使用的表达式
为代码问题而做的检查。 用户可以通过本检查来控制某些代码的使用。比如,禁止在代码中使用"System.out.println"的检查:
<module name="GenericIllegalRegexp">
<property name="format" value="System\.out\.println"/>
</module>
其中"format"属性指定了非法的字符的正则表达式的格式。("."用"\."表示),完整的属性表如所示。
(2).文件结尾的回车
检查文件末尾是否有一个回车。
原理:源文件和文本文件一般应该以一个新行(回车)作为结尾。
特别是在使用源代码控制系统比如CVS的时候。如果没有以新行作为文件结尾,CVS甚至会显示警告。
本检查应该放在<module name = "Checker">结点下。
默认检查:
<module name="ewlineAtEndOfFile"/>
检查使用LINUX风格的换行符:
<module name="NewlineAtEndOfFile">
<property name="lineSeparator" value="lf"/>
</module>
只检查java, xml 或python文件:
<module name="NewlineAtEndOfFile">
<property name="fileExtensions" value="java, xml, py"/>
</module>
(3).没有被注释掉的Main函数
检查没有被注释掉的main函数
原理:Main()函数通常被用于调试,在JUnit出现之后Main()有所减少,但是也有人喜欢用。
我们调试完后很容易就忘掉删了它。 它修改了API,增加了class或者jar文件的体积。
所以,除了正常的程序入口之外,所有的main方法都应该被删掉或注释掉。
默认检查:
<module name="UncommentedMain"/>
可以设置"excludedClasses"属性来不检查某个类,类型是正则表达试,默认值是"^$"。如果不想检查名称中以"Main"结尾的类,可以这样:
<module name="UncommentedMain">
<property name="excludedClasses" value="^Main&"/>
</module>
(4).大写的L
检查并确保所有的常量中的L都是大写的。也就是在常量中没有使用”l”而是用的”L”,比如long型常量,都要以”L”结尾。
这与Sun编码规范 3.10.1 相一致。小写的字母l 跟数字1 太象了。
<module name="UpperEll"/>
(5).声明数组的风格
检查数组类型的定义。有两种风格:java风格的: String[] args 或者 C/C++ 风格的:String args[]
检查是否使用了java风格:
<module name="ArrayTypeStyle"/>
检查是否使用了C风格:
<module name="ArrayTypeStyle">
<property name="javaStyle" value="false"/>
</module>
(6).缩进
检查java代码的缩进
因为"tab"在不同的文本编辑器下的缩进是不同的,所以最好都使用空格。
默认配置:基本缩进 4个空格,新行的大括号:0。新行的case 4个空格。
<module name="Indentation"/>
(7).必须出现的字符串
确保代码中存在某个字符串的检查。该检查不关心它出现的位置在哪儿,只要它出现了就可以。
比如,检查代码中必须出现了版权的字样, “This code is copyrighted”:
<module name="RequiredRegexp">
<property name="format" value="This code is copyrighted"/>
</module>
"format"属性指定了 必须出现的字符串的 正则表达式。默认是空。"^$"
<!--[endif]-->