eclipse pmd的使用

上篇讲了findbugs的使用,这篇就来说下pmd的使用。

PMD是一种开源分析Java代码错误的工具。与其他分析工具不同的是,PMD通过静态分析获知代码错误。也就是说,在不运行Java程序的情况下报告错误。PMD附带了许多可以直接使用的规则,利用这些规则可以找出Java源程序的许多问题。此外,用户还可以自己定义规则,检查Java代码是否符合某些特定的编码规范。

因为好像直接在eclipse里面直接安装好像那网站的镜像不行了,所以我们选择离线安装。

工具/原料

  • pmd插件包。下载地址http://pan.baidu.com/s/1i3r6SJV

安装方法/步骤

  1. 1

    解压文件中的压缩文件,将里面的两个文件夹plugins和 features下面的文件分别拷贝到eclipse目录下面对应的plugins和features目录,重启eclipse。

  2. 2

    Eclipse中,选择Windows->Preferences,即可看到已添加的Pmd,如下图所示

    技术分享
    END

配置方法/步骤

  1. 1

    启动Eclipse IDE,打开工程,选择 "Windows"->"Preferences"下的PMD项,其中Rules Configuration 项目可以配置PMD的检查规则,自定义检查规则也可以在此通过Import的方式导入到PMD中

    技术分享
  2. 2

    对于不需要的规则,可以选中该规则,点击“remove rule”删除规则,也可以点击“import rule”导入新的规则,配置好后,鼠标右键点击工程中需要检查的JavaSource,

  3. 选择PMD-->Find suspect cut and paste。检查结果会放在reports目录下,文件名为cpd-report.txt。

  4. 可以通过使用Eclipse的帮助系统来查看PMD插件的文档。

    在安装完更新后,如果发生了一个异常,例如”java.lang.RuntimeException: Could not find that class xxxx”,这时试着删除workspace中的.metadata/plugins/net.sourceforge.pmd.eclipse目录下的 ruleset.xml文件。

    之后PMD就会通过规则检查你的JavaSource了并且将信息显示在PMD自己的视图上
  5. 选择“pmd”-->"check code with pmd",然后进入某个java文件,会出现一些报错,然后你放在上面呢会有一些提示,比如:

  6. 技术分享
    技术分享
    技术分享

  7. 我就不一一贴图来解释了,请看下面的解释哈,百度文库里面总结的非常实用啊。

  8. 1.    Avoidunnecessary Comparisons in Boolean exception.(Boolean类型重复判断)

    错误  例子: if(null! = a && a.size>0)

    正确       if(null! = a && false == a.IsEmpay())

    2. Avoid Usingimplementation types like (ArrayList HashMap/ LinkedHashMap) ,use the interfaceinstand.(用数组的接口类型)

       错误  例子:ArrayList<String> arraylist=newArrayList<String>();

       正确          List<String>     list=newArrayList<String>();

    错误  例子: private static HashMap map=new HashMap();

       正确       privatestatic Map map=new HashMap(); 

    错误  例子: private static LinkedHashMap map=newLinkedHashMap();

       正确       privatestatic Map map=new LinkedHashMap(); 

    3. Method names should not start with capital letters(方法名不能以大写开头)。

    错误  例子: public class  Start()

    正确      public  class  start() 可以用快捷键 Alt+shift+R全部替

    4.varivable      that are final and static should be in allcaps.(定义的参数必须大写)

    错误  例子:public static  final  String root

    正确      public  static  final String  ROOT

    5.Avoidappending charcutars as Strings in StringBuffer append (避免在StringBuffer里附加单个字符时附加成String类型)

    错误  例子: buf.append(“)”)或者buf.append(“a”)

    正确       buf.append(‘)‘)或者 buf.append(‘a‘)

    6.use ArrayList instanded of vector(使用ArrayList替换vector后还是会报错,所以直接改成是以它的接口形式替换)

    错误  例子: vector<String>keys = new vector<String>(ELE);

    正确       List<String> keys = new ArrayList<String>(ELE);   

    7. Variables that are not final should not containunderscores (except for underscores in standard prefix/suffix) (变量不是final类型的不能包含下划线)

    错误  例子: private int DEAULT_PORT = 8001;

    正确        private intDEAULTPORT = 8001;(调用它的所有类都需要改动)

    8. Variables should start with a lowercase character(参数必须要以小写开始)

    错误  例子: private static int HANDLE_MAX = 200;

    正确      private static int handleMax= 200;

    9. Using equalsIgnoreCase() is cleaner than usingtoUpperCase/toLowerCase().equals().

    错误  例子:

    正确

    10. Unnecessary wrapper object creation

    错误  例子: intCurPage =Integer.valueOf(curPage).intValue();

    正确      intCurPage = Integer.parseInt(curPage);

    11. This is aninefficient use of StringBuffer.toString; call StringBuffer.length instead.    错误  If(newPartLen+smsMOCommondArr.toString().getBytes(DB_CHARSET).length> DB_VERCHAR_MAX_LEN + 1) {}

    正确 if(newPartLen+(smsMOCommondArr.toString().getBytes(DB_CHARSET)).length> DB_VERCHAR_MAX_LEN + 1) {}  

    12. This final field could be made static

    错误  例子: private final String urlPrefix = "http://";

    正确       private static final String URL_PREFIX = "http://";

    13. The field name indicates a constant but its modifiersdo not

    错误  例子: private static String CONF_NAME = "version";

    正确      private static final String CONF_NAME = "version";

    14. System.out.print is used

    错误  例子: System.out.println("PartalOneAppender--message=["+message+"]");

    正确     //System.out.println("PartalOneAppender--message=["+message+"]");

    15. Switch statements should have a default label

    错误  例子: switch (Type)

            {

                case USER:

                    displayType = "USER";

                    break;

                case ADMIN:

                    displayType = "ADMIN";

                    break

            }

    正确       switch (Type)

            {

                case USER:

                    displayType = "USER";

                    break;

                case ADMIN:

                    displayType = "ADMIN";

                    break;

     default:

            }

    16. Substitute calls to size() == 0 (or size() != 0) withcalls to isEmpty()

    错误  例子:  if(null==Handlers || 0 ==Handlers.size())

    正确        if (null==Handlers || Handlers.isEmpty())

    17. Return an empty array rather than null.

    错误  例子: if (null != g && g.length > 0)

            {

                String[] cloneGroups = new String[g.length];

                System.arraycopy(g, 0, cloneGroups, 0,g.length);

                return cloneGroups;

            }

            return null;

    }

    正确 if (null != g && g.length > 0)

            {

                String[] cloneGroups = new String[g.length];

                System.arraycopy(g, 0, cloneGroups,0, g.length);

                return cloneGroups;

            }

            return new String[0];

    18. Deeply nested if..then statements are hard to read

    原因:  深嵌套的if循环很难读懂。

    报错例子  

    if (null != portalScriptionInfo &&null != portalScriptionInfo.getChargeInfo()){

    if(productId.equals(portalScriptionInfo.getChargeInfo().getSourceChargeId()))

    {// 构造orderInfo 对象

    portalOrderInfo.setProductId(productId);

    productName = chargeInfo.getProductName();

    break;

       }

        }

    修改后的例子

         if (null != portalScriptionInfo&& null!=portalScriptionInfo.getChargeInfo()&&(productId.equals(portalScriptionInfo.getChargeInfo()

                                               .getSourceChargeId())))

    {

      portalOrderInfo.setProductId(productId);

      productName = chargeInfo.getProductName();

       break;

    }

    19. Caught exception is rethrown, original stack trace maybe lost

    原因: 捕捉一个异常后,再从新把异常扔出去,会把以前的异常信息丢掉。

    修改: 可以把在此扔出的异常信息以Log日志的形式打印出来。   

    例如:  (错误) catch (IOException ioe)

    {

     String msg = "Can‘t open config file: " + xmlFile + " due to: "

                        + ioe;

                throw new IOException(msg);

            }

    改正后:catch (IOException ioe)

            {

    String msg = "Can‘t open config file: " + xmlFile + " dueto: "

                        + ioe;

    LogFactory.getInstance().logAction(msg);  }

    20.Avoid throwing raw Exception types(避免抛出一个生疏的异常类型)

    错误  例子: catch (IOException ioe)

     {

               ioe.printStackTrace();

    String msg = "Can‘t open config file: " + xmlFile.getAbsolutePath()+ " dueto: " + ioe;

               throw new Exception(msg);}

    正确  catch (IOException ioe)

    {

               ioe.printStackTrace();

    String msg = "Can‘t open config file: " + xmlFile.getAbsolutePath()+ " dueto: " + ioe;

    LogFactory.getInstance().logAction(msg);}

    21. Method call on object which maybe null

    错误  例子: if (GroupList == null && GroupList.size() < 1)

    正确      if (GroupList.isEmpty())

    22. It is somewhat confusing to have a field name with thesame name as a method.

    原因:A ‘getX()‘ method which returns a booleanshould be named ‘isX()‘  属性名与方法名称相似。

    修改:错误 private boolean stopServer;

            public void stopServer() {

           this.stopServer = true;

    }

    正确  可以把方法名称该换一个名字!

    23. Do not use if statements that are always true oralways false

    原因:  不要总使用If循环条件是true或者是false。

    修改:  (错误的)

    StringNameKey = request.getParameter("NameKey");

    if (true) {

               request.setAttribute("NameKey", nameKey);

                ReleaseContent releaseContent = newReleaseContent();

               releaseContent.setCatalogId(catalogId);

                User user= super.getUser(request);

                int userType =userInfo.getUserType();

               …………………

    (正确的)ift条件是真的就可以去掉if(true)

     String NameKey =request.getParameter("NameKey");

    //if (true) {

               request.setAttribute("NameKey", nameKey);

                ReleaseContent releaseContent = newReleaseContent();

               releaseContent.setCatalogId(catalogId);

                User user= super.getUser(request);

                int userType =userInfo.getUserType();

               …………………

    24. System.arraycopy is more efficient

    报错的例子: for (int i1 = 0; i1 <tmpabcde.length; i1++)

            {

                tmpabcde[i1] = digestInt[i1];

                  }

    修改成     for (int i1 = 0; i1 < tmpabcde.length; i1++)

            {//     tmpabcde[i1] = digestInt[i1];

                System.arraycopy(digestInt, i1, tmpabcde, i1,1);

                   } 

    ** arraycopy(Object src,int srcPos, Object dest,int destPos, int length)
              从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。

    参数: src - 源数组。  srcPos - 源数组中的起始位置。

    dest - 目标数组。 destPos - 目标数据中的起始位置。

    length - 要复制的数组元素的数量。

    25.use aslist instended of tight loops()

    原因  for(int i = 0; i < type.length; i++) {

                List.add(type [i]); }

    修改: List = Arrays.asList(type);

    **  提供了一个创建固定长度的列表的便捷方法,该列表被初始化为包含多个元素:

    List list=Arrays.asList("Larry", "Moe", "Curly");

    参数:Larry : 存放的类型   Moe: 有效性         curly:

    26.Avoid empty if statements()

       原因:在if循环中没有大括号。

    做法:

    错误  例子: if (mlang == null)

               mlang = LanguageUtil.getDefaultLanguage();

           return "_" + mlang.getLanguage().toUpperCase() +"_"

                    + mlang.getCountry().toUpperCase();

    正确    if (mlang == null)

           {

               mlang = LanguageUtil.getDefaultLanguage();

           }

           return "_" + mlang.getLanguage().toUpperCase() +"_"

                    +mlang.getCountry().toUpperCase();

    27. Avoid using (if...else/ if/ for/ while) statementswithout curly braces

    原因:  避免使用(if...else/ if/ for/ while)循环时没有波形括号(基本的语法错误)

    修改:  应该加括号的地方加上括号。

    28. Avoid using exceptions as flow control.

    原因:  避免使用异常来控制流程

    修改:  报出的异常信息基本上都是在try。。。catch。。的catch语句块中,可以

    把在catch语句块中抛出的异常信息,用log日志来代替输出信息。

    29. Avoid unnecessary if..then..else statements whenreturning a Boolean

    原因: 在返回值是Boolean类型时,避免不必要的使用if..then..else

    修改:

    错误的:if (UserConstant.TYPE_SP ==getUser(request).getUserType())

            {

                return true;

            }

            else

            {

                return false;

            }

    正确的:if (UserConstant.TYPE_SP ==getUser(request).getUserType())

            {

                return true;

            }

            return false;

    30. Avoid unnecessary constructors - the compiler willgenerate these for you.

    原因:  产生了一个多余的构造器,编辑器将为你产生它们。

    做法:  一个公有的抽象类,不需要自己在写一个构造器,因为它本身自己就可以

    提供构造方法。删除多余的私有构造方法。

    31. Avoidinstantiating Boolean objects; reference Boolean.TRUE or Boolean.FALSE or callBoolean.valueOf() instead.

    错误  例子:  request.setAttribute("productNotFound",Boolean.valueOf("true"));

    正确        request.setAttribute("productNotFound", Boolean.TRUE);

    **Boolean类型的值不需要值类型转换,直接可以赋以true或者是false;

    32. Avoid catching NullPointerException; considerremoving the cause of the NPE.

    原因:避免捕捉产生的空指针(排除由它造成的NPE原因)

    做法:  删除语句块中抛出的异常信息,由Log日志来带它打印信息

    33. Avoid calling toString() on String objects; this isunnecessary.

    错误  例子: String result = "";

    return result.toString();

    正确      return result;

    **    本来就是String类型不需要再toString()转换;

    34. An empty statement (semicolon) not part of a loop.

    原因:    if (is != null) {

                  try{

                      is.close();

                  }

                  catch(Throwable u) {

                      ;

                }

    正确   如果该方法没有任何的代码,你就可以使用日志来记录它的异常信息。

    35. A throw statement in a finally block makes the controlflow hard to understand.

    原因:不要在finally语句块中抛出异常,会造成一个很难理解的控制流。

    做法:可以把抛出的异常信息,用log日志的形式来替换。

    36. Avoid really (long/short) parameter lists.

    原因:方法参数名太长。

    做法:

    37. No need to import a type that lives in the samepackage

    原因:不需要导入类型相识的架包。

    做法:使出这个多余的架包。       

    38. No need to call String.valueOf to append to a string.

    原因:  它把String类型的值再一次转化为String类型的值,是多余的。

    做法: 不用转化它的值类型,因为它本身就是String类型的值。    

    39. A method/constructor shouldn‘t explicitly throwjava.lang.Exception

    原因:方法不能扔出一个不具体的异常信息。

    做法:根据具体的代码,抛出具体的异常信息。

    40. Avoid using implementation typelike( ‘TreeMap‘/‘java.util.HashSet‘/‘java.util.HashSet‘)

    use theinterface instead

    错误  例子:TreeMap map=NEW TreeMap();

    正确       Map   map=NEW TreeMap();

    41. Avoid unused imports such as‘org.apache.struts.action.ActionMessages‘

    原因: 导入了多余的架包,例如:org.apache.struts.action.ActionMessages

    做法:删除掉。同时也可以用快捷键先ctrl+A,再ctrl+shift+o就可以了。       

    42. Avoid returning from a finally block

    原因:   返回信息在finally块中出现。

    做法   避免返回信息出现在finally块中。 

    43. All methods arestatic. Consider using Singleton instead. Alternatively, you could add aprivate constructor or make the class abstract to silence this warning.

    原因: 当方法都是静态的,建议使用使用私有的构造器,或者把这个类命名为abstract

    正确  例如:

    (错误)public class AlarmQueue extends Thread

    {

        private static User user = LogFactory.getInstance();

    private static Queue ALARMQUE = new Queue();

    }

     (正确)public final class AlarmQueue extends Thread

    {

        private static User user = LogFactory.getInstance();

    private static Queue ALARMQUE = new Queue();

    private AlarmQueue(){}//私有的构造器

    }

    或者改成

    public abstract class AlarmQueue extends Thread{}

    44. A getX() method which returns a boolean should benamed isX()

    原因: 当放方法返回的参数是boolean类型,它的方法名称应前加上is。

    正确 例如: 错误:public class Boolean getX(){}

                 改为:publicclass Boolean isX() {}  

    45. A switch with less than 3 branches is inefficient, usea if statement instead.

    原因: 用swith….catch….进行判断时,条件必须达到是3个以上,循环条件少于3

    个使用if循环来代替。

    正确 把  swith….catch….循环判断,改成if循环。

    46. Avoid importing anything from the ‘sun.*‘ packages

    原因:  避免导入sun.*的有关架包。

    做法:删除掉这个sun.*的架包。      

    47. Avoid printStackTrace(); use a logger call instead.

    原因:在捕捉异常时打印异常信息。

    正确:可以把打印的异常信息,用log日志通知来替换。

    通过对PMD错误的修改,我总结了以下几点:

    1.在编写代码过程中,对类,接口,方法,参数的命名,应该注意:“常量应该使用全大写英语名”,属性名可以和公有方法参数相同,不能和局部变量相同。

    2.如果是Boolean类型的参数,在写方法体是最好是以Isxxxx()开始,减少在PMD检查中出现错误信息,并且方法名不能过长或者过少,最好在15字母左右。

    3.在使用接口时,例如ArrayList  要使用它的接口类型数组List。

    4.尽量在代码中不要出现System.out.println();这类的打印信息,在PMD检查时会出现错误。

    5.在使用循环语句是,如果循环条件少于3个就用“IF” 循环,循环条件多于三个以上的就可以使用swtich……catch………循环,使用swtich……catch………循环时必须要至少有一个default;

    6.在try….catch()……语句块中抛出异常时,尽量避免打印异常信息,可以用日志来记录异常信息。

     并且再捕获异常时尽量不要直接的抛出异常,而是要把异常细化后,在处理。

    7例如:for (int i = 0; i <type.length; i++) {循环中

                List.add(type [i]); }//不再使用

    而是用List list=Arrays.asList("Larry", "Moe", "Curly");来替换,给了一个固定大小的数组,并且在效率上远远大于add()方法。

    8.在使用String类型获取单个字符时,最好使用StringBuffer()来获取从效率上节省了系统了开支。

    9.类中没有实现的接口,应该定义成一个abstract方法,类定义成abstract类。

    10.在初始化时,不要使用类的非静态属性。

    11.避免在同步方法中调用另一个同步方法造成死锁。

    12.在clone()方法中必须应该且必须实现super.Clone()。而不是NEW。
  9. 好了,解决的方法也说了,然后你可能不想去改了,也对报错看的不爽,那么你可以clear pmd violations,然后你会发现不在会出现错误标示,并且然后violations outlines也会清空,是不是感觉改bug特别的方便。


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。