CheckStyle 和findbugs 验证代码质量工具

CheckStyle是什么?

  CheckStyle是SourceForge下的一个项目,提供了一个帮助JAVA开发人员遵守某些编码规范的工具。它能够自动化代码规范检查过程,从而使得开发人员从这项重要,但是枯燥的任务中解脱出来[1]。

  2.2. CheckStyle检验的主要内容

  CheckStyle默认提供一下主要检查内容:

  ·Javadoc注释

  ·命名约定

  ·标题

  ·Import语句

  ·体积大小

  ·空白

  ·修饰符

  ·块

  ·代码问题

  ·类设计

  ·混合检查(包活一些有用的比如非必须的System.out和printstackTrace)

  从上面可以看出,CheckStyle提供了大部分功能都是对于代码规范的检查,而没有提供象PMD和Jalopy那么多的增强代码质量和修改代码的功能。但是,对于团队开发,尤其是强调代码规范的公司来说,它的功能已经足够强大。

  2.3. CheckStyle的主要运行方式

  目前,CheckStyle的版本是3.0,与以前的版本不同,它的配置文件是基于XML而非Properties文件。

  它的3.0版本提供了两种运行的方式:

  ·命令行工具

  ·ANT任务

  同时,CheckStyle目前有很多针对流行IDE的插件,例如Eclipse、IntelliJ IDEA、JBuilder等。但是,大部分都是基于2.4的版本,新版本的特性不支持,同时配置也较为复杂。

  因为一般情况下,如果与开发过程与环境集成起来,编码规范的检查会更加有效,因此,作为ANT任务的运行方式使用的更加普遍。

  在ANT的build.xml文件中添加CheckStyle任务的步骤如下:

  1. 将checkstyle-all-3.1.jar拷贝到项目的LIB目录;

  2. 建立配置文件;

  3. 声明CheckStyle任务:

<taskdef resource="checkstyletask.properties" classpath="${lib}/checkstyle-all-3.1.jar"/>

  4. 建立CheckStyle任务:

<target name="checkstyle">
<checkstyle c>
<fileset dir="${src}" includes=" **/*.java" />
</checkstyle>
</target>

  2.4. 定制CheckStyle

  CheckStyle的执行基于XML配置文件,它的主要组成部分是:

  ·Module:整个配置文件就是一棵Module树。根节点是Checker Module。

  ·Properties:它来决定一个Module如何进行检查。每个Module都有一个默认值,如果不满足开发需求,可以设定其它的值。

  下面是一个示例:

<module name="MethodLength">
<property name="max" value="60"/>
</module>

  它表示,如果方法或者构造函数的长度超过60行,CheckStyle就会报错。而默认值是150行。

  以下是一段CheckStyle对于Maven项目源文件的检查报告:

Method 'createExpression' is not designed for extension - needs to be abstract, final or empty. 91
Unable to get class information for JellyException. 91
Line has trailing spaces. 93
Line has trailing spaces. 104
Method 'evaluate' is not designed for extension - needs to be abstract, final or empty. 113
Parameter context should be final. 113
Line has trailing spaces. 130
Method 'getExpressionText' is not designed for extension - needs to be abstract, final or empty. 131
Line has trailing spaces. 134
Line has trailing spaces. 135
Method 'toString' is not designed for extension - needs to be abstract, final or empty. 137
Method 'isSupportAntVariables' is not designed for extension - needs to be abstract, final or empty. 156
Method 'setSupportAntVariables' is not designed for extension - needs to be abstract, final or empty. 168
Parameter supportAntVariables should be final. 168
'supportAntVariables' hides a field. 168
Method 'isValidAntVariableName' is not designed for extension - needs to be abstract, final or empty. 183
Parameter text should be final. 183

  一般情况下,与IDE集成在一起使用的时候,点击出错的条目,可以跳转到相应的代码。
本贴来自ZDNetChina中文社区http://bbs.zdnet.com.cn,本贴地址:http://bbs.zdnet.com.cn/viewthread.php?tid=178617




三、CheckStyle的最佳实践

  3.1. Sun’s Code Conventions的修改

  在CheckStyle的最新发布版本中,有一个对于Sun的Java编码规范的配置文件信息。但是,其中有很多条目并不一定符合项目开发的需要。就算是对于很多优秀的开源项目,按照这个规范来进行检查,也会出现成千上万的错误。

  下面提出的一些修改意见,是从实际项目执行过程中总结出来的,可以作为大家的参考。我们以CheckStyle3.0配置文件的顺序来介绍:

  1. 去除对于每个包都有一个package.html文件的限制;

<!--<module name="PackageHtml"/>-->
  
  2. 修改对于JavaDoc Comments的限定:对于很多使用Code Generator的项目来说,需要将手写代码与生成代码、单元测试代码的检查分开进行;

  3. 修改对于体积大小的限制:目前,很多显示器都是17寸,而且打印方面的限制也比以前有所改善,同时,由于代码中Factory等模式的运用,以及有意义的方法名称等约定,默认每行代码的长度(80)是远远不能满足要求;对于方法长度等等,也应该根据项目情况自行决定:

<module name="FileLength"/>
<module name="LineLength">
<property name="max" value="120"/>
</module>
<module name="MethodLength">
<property name="max" value="300"/>
</module>
<module name="ParameterNumber"/>

  4. 修改对于Throws的的限制:允许Throws Unchecked Exception以及Throws Subclass Of Another Declared Exception。

<module name="RedundantThrows">
<property name="allowUnchecked" value="true"/>
<property name="allowSubclasses" value="true"/>
</module>

  5. 修改成员变量的可视性:一般情况下,应该允许Protected Members以及Package Visible Members。

<module name="VisibilityModifier">
<property name="protectedAllowed" value="true"/>
<property name="packageAllowed" value="true"/>
</module>

  3.2. CheckStyle应用的最佳实践

  采用CheckStyle以后,编码规范的检查就变得及其简单,可以作为一项切实可行的实践加以执行。

  一般情况下,在项目小组中引入CheckStyle可以按照下面的步骤进行:

  1. 强调Code Review与Code Conventions的重要作用;

  2. 介绍CheckStyle;

  3. 初步应用CheckStyle:参照CheckStyle附带的配置文件,酌情加以剪裁,在项目的Ant配置文件中,添加CheckStyle任务,可以单独执行;

  4. 修改、定型CheckStyle的配置文件:按照基本配置文件执行一段时间(2~3周),听取开发人员的反馈意见,修改配置信息;

  5. 作为开发过程的日常实践,强制执行CheckStyle:稳定CheckStyle的配置信息,同时将CheckStyle任务作为Build的依赖任务或者配置源码控制系统(目前,CheckStyle可以与CVS有效集成),使得代码在加入系统之前必须通过检查。

  同时需要指出的是,CheckStyle的有效执行需要依赖两个条件:

  ·Ant的广泛应用:CheckStyle基于Ant执行的方式比较容易,而且可以在项目内容形成一致的执行环境。同时,也比较容易与其它任务,例如Build等发生关联。

  ·IDE Format Code的强大功能:由于CheckStyle本身并没有提供很强大的Code Format等功能,因此,需要借助IDE的帮助,从而使得在发生错误的时候,可以很容易的进行修复。目前,主流的Java IDE都提供了这方面的功能,IDEA在这方面尤其突出。它提供的统一、可定义的Code Format Template(项目小组内部可以使用统一模板)以及方便的快捷键功能(Ctrl+Alt+T:Format Code, Ctrl+Alt+O:Optimize Import等)。

  四、结论

  利用CheckStyle可以方便的对于编码的Code Conventions进行检查,同时,也有效地减少了Code Review的工作,使得Reviw人员的精力更多的集中到逻辑和性能检查。

Checkstyle的结果输出

序号      输出内容意义

1 Type is missing a javadoc commentClass  缺少类型说明

2“{” should be on the previous line “{” 应该位于前一行

3Methos is missing a javadoc comment方法前面缺少javadoc注释

4Expected @throws tag for “Exception”在注释中希望有@throws的说明

5“.” Is preceeded with whitespace “.” 前面不能有空格

6“.” Is followed by whitespace“.” 后面不能有空格

7“=” is not preceeded with whitespace“=” 前面缺少空格

8“=” is not followed with whitespace“=” 后面缺少空格

9“}” should be on the same line“}” 应该与下条语句位于同一行

10Unused @param tag for “unused”没有参数“unused”,不需注释

11Variable “CA” missing javadoc变量“CA”缺少javadoc注释

12Line longer than 80characters行长度超过80

13Line contains a tab character行含有”tab” 字符

14Redundant “Public” modifier冗余的“public” modifier

15Final modifier out of order with the JSL suggestionFinal modifier的顺序错误

16Avoid using the “.*” form of importImport格式避免使用“.*”

17Redundant import from the same package从同一个包中Import内容

18Unused import-java.util.listImport进来的java.util.list没有被使用

19Duplicate import to line 13重复Import同一个内容

20Import from illegal package从非法包中 Import内容

21“while” construct must use “{}”“while” 语句缺少“{}”

22Variable “sTest1” must be private and have accessor method变量“sTest1”应该是private的,并且有调用它的方法

23Variable “ABC” must match pattern “^[a-z][a-zA-Z0-9]*$”变量“ABC”不符合命名规则“^[a-z][a-zA-Z0-9]*$”

24“(” is followed by whitespace“(” 后面不能有空格 25“)” is proceeded by whitespace“)” 前面不能有空格



不太明白的错误解答

1.  'X' hides a field.

public class Foo
{
    private int bar;

    public Foo(int bar)
    {
        this.bar = bar;
    }

    public final int getBar()
    {
        return bar;
    }
}

解释:全局private int bar;和局部public Foo(int bar)的bar变量名字重复。
此错误,可以忽略不检查。


2. Parameter X should be final.


public class Foo
{
    private int bar;

    public Foo(int bar)
    {
        this.bar = bar;
    }

    public final int getBar()
    {
        return bar;
    }
}

解释:public Foo(int bar)的局部变量,被认为是不可改变的,检查需要加上final关键字定义public Foo(final int bar)
此错误,可以忽略不检查。

3. Redundant 'X' modifier.

public interface CacheHRTreeService extends Manager {

/**
  * Organization Tree
  *
  * @param orgDto
  * @return
  * @throws Exception
  */
public void setOrganization(OrganizationDTO orgDto) throws Exception;

/**
  * Organization Tree
  *
  * @return
  * @throws Exception
  */
public OrganizationDTO getOrganization() throws Exception;
......
}

解释:多余的字段。public OrganizationDTO getOrganization() throws Exception;此时public为多余的字段,因为interface定义的时候,就是public的。

需要检查。

4. - Class X should be declared as final.

解释:对于单例设计模式,要求返回唯一的类对象。但是HRFactory和ContextFactory为优化的两个类,不需求检查。
其他的单例类,依然需要进行检查。


5.  Utility classes should not have a public or default constructor.

解释:工具类不必提供默认的构造方法。
需要检查,仅仅为提示。

6. File does not end with a newline.
解释:虽然JAVA程序不要求结尾要用新行,但是习惯上应该要空一行。
需要检查,仅仅为提示。

7. - Method 'addChildrenId' is not designed for extension - needs to be
  abstract, final or empty.

解释:通过父类继承的,此类有点特殊
可以忽略此类。

8. Variable 'id' must be private and have accessor methods.
解释:BaseHRDTO类,为父类,属性给子类继承,比较特殊。
但是其他的类,声名需要加上范围'private'关键字
需要检查。

9. -Array brackets at illegal position.
解释:代码写法,习惯不一样。
需要检查,仅仅提示。



FindBugs(http://findbugs.sourceforge.net/)版本1.1.1
简介:findbugs是一个在java程序中查找bug的程序,它查找bug模式的实例,也就是可能出错的代码实例,注意findbugs是检查java字节码,也就是*.class文件。
自带检测器的介绍:findbugs自带60余种Bad practice,80余种Correntness,1种Internationalization,
   12种Malicious code vulnerability,27种Multithreaded correntness,23种Performance,43种Dodgy。

Bad practice坏的实践
一些不好的实践,下面列举几个:
HE:类定义了equals(),却没有hashCode();或类定义了equals(),却使用Object. hashCode();或类定义了hashCode(),却没有equals();或类定义了hashCode(),却使用Object.equals();类继承了equals(),却使用Object.hashCode()。
SQL:Statement的execute方法调用了非常量的字符串;或Prepared Statement是由一个非常量的字符串产生。
DE:方法终止或不处理异常,一般情况下,异常应该被处理或报告,或被方法抛出。

Correctness一般的正确性问题
可能导致错误的代码,下面列举几个:
NP:空指针被引用;在方法的异常路径里,空指针被引用;方法没有检查参数是否null;null值产生并被引用;null值产生并在方法的异常路径被引用;传给方法一个声明为@NonNull的null参数;方法的返回值声明为@NonNull实际是null。
Nm:类定义了hashcode()方法,但实际上并未覆盖父类Object的hashCode();类定义了tostring()方法,但实际上并未覆盖父类Object的toString();很明显的方法和构造器混淆;方法名容易混淆。
SQL:方法尝试访问一个Prepared Statement的0索引;方法尝试访问一个ResultSet的0索引。
UwF:所有的write都把属性置成null,这样所有的读取都是null,这样这个属性是否有必要存在;或属性从没有被write。

Internationalization国际化
当对字符串使用upper或lowercase方法,如果是国际的字符串,可能会不恰当的转换。
   
   Malicious code vulnerability可能受到的恶意攻击
   如果代码公开,可能受到恶意攻击的代码,下面列举几个:
   FI:一个类的finalize()应该是protected,而不是public的。
   MS:属性是可变的数组;属性是可变的Hashtable;属性应该是package protected的。
  
   Multithreaded correctness多线程的正确性
   多线程编程时,可能导致错误的代码,下面列举几个:
   ESync:空的同步块,很难被正确使用。
   MWN:错误使用notify(),可能导致IllegalMonitorStateException异常;或错误的
使用wait()。
No:使用notify()而不是notifyAll(),只是唤醒一个线程而不是所有等待的线程。
SC:构造器调用了Thread.start(),当该类被继承可能会导致错误。
  
   Performance性能问题
   可能性能不佳的代码,下面列举几个:
   DM:方法调用了低效的Boolean的构造器,而应该用Boolean.valueOf(…);用类似
Integer.toString(1)代替new Integer(1).toString();方法调用了低效的float的构造器,应该用静态的valueOf方法。
SIC:如果一个内部类想在更广泛的地方被引用,它应该声明为static。
SS:如果一个实例属性不被读取,考虑声明为static。
UrF:如果一个属性从没有被read,考虑从类中去掉。
UuF:如果一个属性从没有被使用,考虑从类中去掉。
  
    Dodgy危险的
   具有潜在危险的代码,可能运行期产生错误,下面列举几个:
   BC:对抽象集合如List、Set的造型;对具体集合如ArrayList、HashSet的造型;
未检查或无法保证的造型;
CI:类声明为final但声明了protected的属性。
DLS:对一个本地变量赋值,但却没有读取该本地变量;本地变量赋值成null,却没有读取该本地变量。
ICAST:整型数字相乘结果转化为长整型数字,应该将整型先转化为长整型数字再相乘。
INT:没必要的整型数字比较,如X <= Integer.MAX_VALUE。
NP:对readline()的直接引用,而没有判断是否null;对方法调用的直接引用,而方法可能返回null。
REC:直接捕获Exception,而实际上可能时RuntimeException。
ST:从实例方法里直接修改类变量,即static属性。

自定义检测器:findbugs提供了强大的自定义检测器的功能,首先我们应该清楚需要
检查的案例,findbugs的官方文档里并没有详细的介绍如何自定义,那我们只能直接阅读它的源码了,着重阅读BytecodeScanningDetector和ByteCodePatternDetector的子类型,它们可以检测一般类型的问题。Findbugs利用了Byte Code Engineering Library(即BCEL,Apache上的一个开源项目),以实现其检测器,所有的字节码扫描都是基于visitor模式。我们可以参照findbugs自带的检测器的类的源码,去编写一个自定义的检测器代码,编写完后编译成类文件,同时我们还需要提供两个XML文件,Findbugs.xml和message.xml,在Findbugs.xml里指定检测器和实现类,检测器的缩写、类型如快速或慢速,而message文件里则包括了该检测器的描述信息,可能是html的,然后将源文件、类文件和上面两个XML文件打包成jar文件,放在findbugs home的plugin文件夹下,这样我们就可以使用自定义检查器了。

参考文档:
FindBugs官方文档(http://findbugs.sourceforge.net/)
FindBugs,第1部分:提高代码质量
http://www-128.ibm.com/developerworks/cn/java/j-findbug1/
FindBugs,第2部分:编写自定义检测器
http://www-128.ibm.com/developerworks/cn/java/j-findbug2/
代码静态分析(http://blog.donews.com/foxgem/archive/2005/04/23/347444.aspx)



Findbugs使用说明<br>目的<br> Findbugs是一个代码质量工具;我们用它来检查源代码中出现的伪问题,以期尽可能在项目的初始阶段将代码问题解决。本文主要介绍Findbugs的eclipse插件的应用。 对应的版本是:Findbugs (0.0.16);eclipse (3.1)<br><br>概要<br> FindBugs 是一个静态分析工具,它检查类或者 JAR 文件,将字节码与一组缺陷模式进行对比以发现可能的问题。我们利用它在eclipse中的插件来对它所过滤的工程的源代码进行检查。希望在程序员编写代码的过程中,将代码中的缺陷指出来,让编码人员在开发中将它们纠正。达到尽可能在项目编码中将问题解决得目的。而不是在编码结束的时候才用该软件对代码检查,修改。<br>

Eclipse插件开发之FindBugs插件:http://soft.yesky.com/480/2291980_1.shtml

猜你喜欢

转载自xiaoqiufeng.iteye.com/blog/1708857