How to improve your code quality---using checkstyl

提高代码的质量,除了要提高逻辑上的控制以及业务流程的理解外,代码本身也存在提高的空间,例如一些潜在的问题可以很早的就避免。类似于编码规范上的内容,如果全靠编码人员进行自行检查,那么无疑需要很大的工作量,如果可以使用代码的静态检查工具进行检查的话,那么将大大的提高编码的效率。
本文是提高代码质量系列文章的第三篇,主要介绍了如何使用checkstyle工具进行代码的自动化检查,以规避一些潜在的问题并找出代码的逻辑错误。
1.        什么是checkstyle?
Checkstyle是一个用于帮助编写Java代码的程序员来遵守特定的编码标准。Checkstyle可以自动进行代码的检查,因为代码检查非常重要,但是又很枯燥,所以可以自动的进行代码检查无疑节省了很多的工作量。Checkstyle尤其适用于强制使用编码标准的项目。
Checkstyle是完全可以进行自定义配置的,并且可以支持几乎任何的编码标准。例如提供了支持Sun Code Conventions编码标准的样例配置文件以及一些其他的样例配置文件。
Checkstyle可以检查源代码的很多方面,checkstyle的本意是检查代码的布局及样式,但是从版本3之后,就已经追加了更多的检查项目。现在的checkstyle版本已经可以检查诸如设计问题,重复代码,以及double checked locking等bug。具体请参考 标准检查项可选检查项
可以在SourceForge的 下载页面下载Checkstyle的最新版本。
相关工具:如果将Checkstyle集成到构建过程中的话,那么将起到最大的作用。Checkstyle的发布版本包含以下内容:
       Ant Task
       命令行工具
另外,也有很多第三方的插件可供使用,例如Eclipse、WSAD、IntelliJ IDEA、NetBeans等流程的Java开发IDE。
2.        CheckStyle的配置
Checkstyle的配置用来指定哪些模块适用于Java源文件。模块是一个以Checker模块为根元素的树结构。modules的下一层元素包括如下的内容:
®       FileSetChecks:一些以输入文件为参数的模块,并引发错误消息。
®       Filters:过滤审核事件的模块,包括错误消息。
®       AuditListeners:报告被接受的事件。
很多检查是TreeWalker FileSetCheck模块的子模块。TreeWalker通过逐个的将Java源文件转换成抽象的语法树,然后循环它的每个子模块来处理检查结果。每个子模块检查各自特定的方面。
Checkstyle从XML文件获取配置,在XML文档中指定了配置的模型的层次以及他们的属性。当使用命令行执行Checkstyle命令(或者在ant任务中使用Checkstyle的时候)是需要提供一个包含配置文档的文件。Checkstyle的发布包中的doc目录中包含了一个样例的配置文件sun_checks.xml可以检查Sun的编码规范。
Modules
XML配置文档中由元素的name属性指定的module元素。下面是一个典型的配置片段:
   
   
       
       
       
   
在上面的配置中:
®       根模块Checker包含了子模块FileSetChecks PackageHtml和TreeWalker。(PackageHtml模块检查所有的包都要有文档)
®       模块TreeWalker包含了子模块AvoidStarImport、ConstantName和EmptyBlock。这些子模块分别检查Java源文件是否有星号引入语句、合法的常两名以及是否包含空块。
对于每个配置模块,checkstyle通过module元素的name属性指定要加载的类。加载模块的类的规则如下:
®       根据指定的包名,例如加载类com.puppycrawl.tools.checkstyle.TreeWalker,,这有助于第三方的模块集成到配置中。
®       checkstyle预定义的包名,例如com.puppycrawl.tools.checkstyle.checks和com.puppycrawl.tools.checkstyle.filters以及它的子包(仅包含在Checkstyle发布版本中)
®       上述规则中与Check连接而成的,例如com.pupycrawl.tools.checkstyle.checks.ConstantNameCheck类的话,可以使用ConstantName作为module的名字
属性
属性用于控制模块如何执行任务的。每个模块的属性都有一个默认值。下面是三个例子用于指定属性:
   
max的默认值为150,可以将其自定义为60,如果默认值可以满足检查的要求,那么就不要修改默认值。
   
   
       
       
       
        ...
   
模块的属性是可以继承的,例如上面例子中的TreeWalker的属性tabWidth,就可以被AvoidStarImport和ConstantName等子模块继承。
属性是可以被扩展的,可以在运行时指定属性的值。
 
               value="${checkstyle.javadoc.severity}"
               default="error"/>
可以在指定属性值后设置一个默认值,当属性值没有被设置时,使用默认的属性值,如上面的例子中checkstyle.javadoc.severity没有被设置时,severity属性的值就是error。
Checker
所有的配置都有一个根模块Checker,Checker包含以下内容:
®       FileSetCheck:用于检查文件的模块
®       Filter:用于过滤审核事件
®       AuditListener:报告被过滤的事件
Checker还定义被所有其他模块继承的属性:
®       basedir:基准目录名,字符串类型,默认值为null
®       localeCountry:区域设置,字符串类型,可以是空字符串或者大写的ISO 3166标准的2个大写代码,默认值为JVM的区域设置
®       localeLanguage:消息的区域语言,字符串类型,可以是空字符串或者是小写的ISO 639代码,默认值是JVM的区域语言
TreeWalker
FilterSetCheck TreeWalker 检查单个的Java源文件,并定义适用于检查这些文件的属性:
®       cacheFile:缓存文件,用于缓存已经通过检查的文件,避免重复检查文件。字符串类型,默认为null
®       tabWidth:tab字符的空格数。整型,默认为8
®       fileExtensions:用于标识java文件的扩展名。字符串类型集合,默认为java
®       charset:文件的编码格式。字符串类型,默认为系统属性file.encoding
   
       
       
             
        ...
   
可以在TreeWalker中写重复的模块来应用不同的检查。
   
   
   
Severity
每个检查都有一个severity属性,这是Checkstyle审查分配给检查的所有违反项。默认的severity等级是error。
使用下面的定义就可以输出转换警告:
   
Filters
checkstyle模块可以包含一系列的Filter子模块用于过滤审查事件,包括checks产生的错误消息。过滤器可以接受获取拒绝审查事件。如果所有的过滤器都接受审查事件,那么checker就报告该事件。
SeverityMatchFilter
这个过滤器根据severity等级来决定审查事件。这个过滤器包含如下的属性:
®       severity:过滤器的severity的等级。severity类型,默认值为error。
®       acceptOnMatch:如果该属性的值为true,那么当且仅当事件的severity等级和属性severity的值相匹配时,才接受审查。如果值为false的话,那么当且仅当事件的severity等级与severity属性值不匹配时才接受审查。boolean型,默认值为true。
   
   
一些其他的过滤器请参考 checkstyles 文档
3.        运行Checkstyle
可以通过两种方式来运行Checkstyle,一种是使用Ant Task,即在Ant构建脚本中执行Checkstyle,另一种就是命令行。当然还有很多IDE的集成插件,在后面进行介绍。
checkstyle的ant task用于在指定的Java文件中运行Checkstyle。checkstyle ant task在Ant 1.5版本下测试完成。 最新版本的Checkstyle中包含了ant task。
最简单的安装方式就是将checkstyle-all-4.4.jar加入到classpath中。这个jar文件中包含了所有运行Checkstyle所需的类。如果不这样做的话,下面的这些类必须添加到classpath中:
®       checkstye-4.4.jar
®       ANTLR 2.7.2中的类,在发布版本中已经包含了这个jar文件
®       Jakarta Commons中的Beanutils类、Collections类、Logging类,这些jar包都包含在发布版本中
®       符合JAXP规范的XML解析器,在JDK 1.4版本以后就已经包含了
如果要使用checkstyle ant task,需要使用taskdef定义checkstyle任务:
         classpath="/path/to/checkstyle-all-4.4.jar"/>
或者假设Checkstyle位于全局的classpath中,可以使用如下的taskdef定义:
checkstyle任务的参数:
file:需要检查的文件。
config:指定配置文件。
configURL:指定配置文件的URL。
(config和configURL中必须指定一个)
properties:指定包含扩展属性值的属性文件。
packageNamesFile:指定一个包含配置的package名的文件。
failOnViolation:如果检查出错误时,是否停止。默认为true。
failureProperty:如果发生错误时,需要设置的属性的名称。
maxErrors:允许发生错误ude最大数。默认为0。
maxWarnings:允许发生的警告的最大数。默认值为整型的最大值。
classpath:查询类时使用的类路径。默认为当前classpath。
classpathref:类路径的引用。
嵌套元素:checkstyle任务支持以下的嵌套元素:。其中元素的参数如下:
type:生成的输出内容的类型,合法的值包括plain和xml。默认的值为plain。
toFile:将输出写入的文件。默认为标准输出。
useFile:是否将输出写入到文件,默认为true。
元素指定提供扩展属性的值的属性文件。该元素的参数如下:
key:属性的键值。
value:字符串格式的属性的值。
file:文件格式的属性的值。
(value和file参数必须设置一个)
下面是一些例子:
 
 
 
 
 
 
 
 
 
            packageNamesFile="myPackageNames.xml"
            file="Check.java"/>
 
        description="Generates a report of code convention violations.">
 
              failureProperty="checkstyle.failure"
              failOnViolation="false">