上篇讲了findbugs的使用,这篇就来说下pmd的使用。
PMD是一种开源分析Java代码错误的工具。与其他分析工具不同的是,PMD通过静态分析获知代码错误。也就是说,在不运行Java程序的情况下报告错误。PMD附带了许多可以直接使用的规则,利用这些规则可以找出Java源程序的许多问题。此外,用户还可以自己定义规则,检查Java代码是否符合某些特定的编码规范。
因为好像直接在eclipse里面直接安装好像那网站的镜像不行了,所以我们选择离线安装。
上篇讲了findbugs的使用,这篇就来说下pmd的使用。
PMD是一种开源分析Java代码错误的工具。与其他分析工具不同的是,PMD通过静态分析获知代码错误。也就是说,在不运行Java程序的情况下报告错误。PMD附带了许多可以直接使用的规则,利用这些规则可以找出Java源程序的许多问题。此外,用户还可以自己定义规则,检查Java代码是否符合某些特定的编码规范。
因为好像直接在eclipse里面直接安装好像那网站的镜像不行了,所以我们选择离线安装。
pmd插件包。下载地址http://pan.baidu.com/s/1i3r6SJV
解压文件中的压缩文件,将里面的两个文件夹plugins和 features下面的文件分别拷贝到eclipse目录下面对应的plugins和features目录,重启eclipse。
Eclipse中,选择Windows->Preferences,即可看到已添加的Pmd,如下图所示
启动Eclipse IDE,打开工程,选择 "Windows"->"Preferences"下的PMD项,其中Rules Configuration 项目可以配置PMD的检查规则,自定义检查规则也可以在此通过Import的方式导入到PMD中
对于不需要的规则,可以选中该规则,点击“remove rule”删除规则,也可以点击“import rule”导入新的规则,配置好后,鼠标右键点击工程中需要检查的JavaSource,
选择PMD-->Find suspect cut and paste。检查结果会放在reports目录下,文件名为cpd-report.txt。
可以通过使用Eclipse的帮助系统来查看PMD插件的文档。
在安装完更新后,如果发生了一个异常,例如”java.lang.RuntimeException: Could not find that class xxxx”,这时试着删除workspace中的.metadata/plugins/net.sourceforge.pmd.eclipse目录下的 ruleset.xml文件。
之后PMD就会通过规则检查你的JavaSource了并且将信息显示在PMD自己的视图上选择“pmd”-->"check code with pmd",然后进入某个java文件,会出现一些报错,然后你放在上面呢会有一些提示,比如:
android studio的pmd安装使用:
插件下载:http://plugins.jetbrains.com/plugin/4596?pr=androidstudio
使用图解:
我就不一一贴图来解释了,请看下面的解释哈,百度文库里面总结的非常实用啊。
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
正确 List
错误 例子: 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
正确 List
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 intHANDLE_MAX = 200;
正确 private static inthandleMax= 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 StringURL_PREFIX = "http://";
13. The field name indicates a constant but its modifiersdo not
错误 例子: private static StringCONF_NAME = "version";
正确 private static final StringCONF_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)
{
caseUSER:
displayType = "USER";
break;
caseADMIN:
displayType = "ADMIN";
break;
}
正确 switch (Type)
{
caseUSER:
displayType = "USER";
break;
caseADMIN:
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;
}
returnnew 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[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 AlarmQueueextends Thread
{
private static Useruser = LogFactory.getInstance();
private static QueueALARMQUE =new Queue();
}
(正确)public final class AlarmQueueextends Thread
{
private static Useruser = LogFactory.getInstance();
private static QueueALARMQUE =new Queue();
private AlarmQueue(){}//私有的构造器
}
或者改成
public abstract class AlarmQueueextends 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
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。好了,解决的方法也说了,然后你可能不想去改了,也对报错看的不爽,那么你可以clear pmd violations,然后你会发现不在会出现错误标示,并且然后violations outlines也会清空,是不是感觉改bug特别的方便。