pmd校验规则总结
错误实例:
?public?class?Foo?{
???public?void?bar()?{
?????int?x?=?0;
?????if?(foo)?x++;//if(foo){x++;}
???}
?}
?
?????
???????????
错误写法示意:????????????????
?
public?void?doSomething()?{
??while?(true)
??????x++;
}
?
??????
???????????
错误写法示意:
?public?void?doSomething()?{
???//?this?is?OK
???if?(foo)?x++;
???//?but?this?is?not
???if?(foo)
???????x=x+1;
???else
???????x=x-1;
?}
?
错误写法示意:
public?void?foo()?{
?for?(int?i=0;?i<42;i++)
???foo();
}
?
?
示例:
public?class?Foo?{
??private?int?bar?=2;
??public?boolean?isBarEqualsTo(int?x)?{
????//?this?bit?of?code
????if?(bar?==?x)?{
?????return?true;
????}?else?{
?????return?false;
????}
????//?can?be?replaced?with?a?simple
????//?return?bar?==?x;
??}
}
???????????
解决办法:建议if嵌套不要超过2层。使用工具方法封装更多的if语句或者把嵌套的if表达式放到同一个层次中。
示例:
public?class?Foo?{
?public?void?bar(int?x,?int?y,?int?z)?{
??if?(x>y)?{
???if?(y>z)?{
????if?(z==x)?{
?????//?whew,?too?deep
????}
???}
??}
?}
}
解决方案:把过深的if逻辑封装到独立的工具方法内,同时尽量让if语句“扁平化”,减少if嵌套
public?class?Foo?{
?public?void?bar(int?x,?int?y,?int?z)?{
??if?(x>y&&y>z)?{//如果这里的判断逻辑比较复杂,则需要使用工具方法封装。时刻别忘了提高代码可读性。
????doSomething(z,x);
??}
?}
Public?void?doSomething(int?z,int?x){
If(z==x){
//....
}
}
}
?
示例:
public?class?Foo?{
?private?void?foo(String?bar)?{
??bar?=?"something?else";
?}
}
?????
示例:
public?class?Foo?{
?public?void?bar(int?x)?{
???switch?(x)?{
?????case?1:?{
???????//?lots?of?statements
???????break;
?????}?case?2:?{
???????//?lots?of?statements
???????break;
?????}
???}
?}
}
?
??????
???????????
示例:
public?class?SeniorClass?{
??public?SeniorClass(){
??????toString();?//may?throw?NullPointerException?if?overridden
??}
??public?String?toString(){
????return?"IAmSeniorClass";
??}
}
public?class?JuniorClass?extends?SeniorClass?{
??private?String?name;
??public?JuniorClass(){
????super();?//Automatic?call?leads?to?NullPointerException
????name?=?"JuniorClass";
??}
??public?String?toString(){
????return?name.toUpperCase();
??}
}
??
Since:?PMD?1.04
Instantiation?by?way?of?private?constructors?from?outside?of?the?constructor's?class?often?causes?the?generation?of?an?accessor.?A?factory?method,?or?non-privitization?of?the?constructor?can?eliminate?this?situation.?The?generated?class?file?is?actually?an?interface.?It?gives?the?accessing?class?the?ability?to?invoke?a?new?hidden?package?scope?constructor?that?takes?the?interface?as?a?supplementary?parameter.?This?turns?a?private?constructor?effectively?into?one?with?package?scope,?and?is?challenging?to?discern.
This?rule?is?defined?by?the?following?Java?class:?net.sourceforge.pmd.rules.AccessorClassGeneration
Example:
????????????????
??
public?class?Outer?{
?void?method(){
??Inner?ic?=?new?Inner();//Causes?generation?of?accessor?class
?}
?public?class?Inner?{
??private?Inner(){}
?}
}
示例:
public?class?Foo?{
?public?final?int?BAR?=?42;?//?this?could?be?static?and?save?some?space
}
??
??????
???????????
示例:
????????????????
?
public?class?Bar?{
?public?void?foo()?{
??Connection?c?=?pool.getConnection();
??try?{
????//?do?stuff
??}?catch?(SQLException?ex)?{
????//?handle?exception
??}?finally?{
????//?oops,?should?close?the?connection?using?'close'!
????//?c.close();
??}
?}
}
?????????
非静态的初始化块将在构造器被调用的时候被访问(优先于调用构造器)。这是一个有效的语言结构,但使用很少且易造成迷惑?
????????????????
示例:
public?class?MyClass?{
?//?this?block?gets?run?before?any?call?to?a?constructor
?{
??System.out.println("I?am?about?to?construct?myself");
?}
}
??????????????
???
调用Collection.toArray时使用集合的规模加上目标类型的空数组作为参数。?????????
示例:
class?Foo?{
?void?bar(Collection?x)?{
???//?A?bit?inefficient
???x.toArray(new?Foo[0]);
???//?Much?better;?this?one?sizes?the?destination?array,?avoiding
???//?a?reflection?call?in?some?Collection?implementations
???x.toArray(new?Foo[x.size()]);
?}
}
?????
在if表达式伴随else子句时,避免在if测试中使用否定表达。例如:不要使用if?(x?!=?y)?diff();?else?same()这种表述,而应该使用if?(x?==?y)?same();?else?diff(),大多数时候使用if(x!=y)形式时不包含else分句,所以一贯地使用此规则能让代码更易于阅读。此外,这也解决了一个细节的排序问题,比如“应该是判断为false的代码块在前面?”,还是“判断通过的代码块在前?”?
示例:
public?class?Foo?{
?boolean?bar(int?x,?int?y)?{
??return?(x?!=?y)???diff?:?same;
?}
}??????????
???????????????????
Example:
?
public?class?Foo?{
?//?Should?specify?Locale.US?(or?whatever)
?private?SimpleDateFormat?sdf?=?new?SimpleDateFormat("pattern");
}
识别出一旦被声明就赋值或通过构造器赋值后就从不改变的私有域,它们将存在的类变成了不变类。这样的域可以是final的?
Example:
public?class?Foo?{
??private?int?x;?//?could?be?final
??public?Foo()?{
??????x?=?7;
??}
??public?void?foo()?{
?????int?a?=?x?+?2;
??}
}
Example:
????????????????
????
class?Foo?{
?//?BAD
?if?(x.toLowerCase().equals("list"))...
?/*
?This?will?not?match?"LIST"?when?in?Turkish?locale
?The?above?could?be
?if?(x.toLowerCase(Locale.US).equals("list"))?...
?or?simply
?if?(x.equalsIgnoreCase("list"))?...
?*/
?//?GOOD
?String?z?=?a.toLowerCase(Locale.EN);
}
因为final类型的class不能被继承,所以不要使用protected域,通过使用private或包访问符来代替以修正你的意图。?
Example:
????????????????
?
public?final?class?Bar?{
?private?int?x;
?protected?int?y;??//?<--?Bar?cannot?be?subclassed,?so?is?y?really?private?or?package?visible???
?Bar()?{}
}
不安全
Example:
????????????????
???
public?class?StaticField?{
???static?int?x;
???public?FinalFields(int?y)?{
????x?=?y;?//?unsafe
???}
}
一个class只有私有的构造函数,但是没有任何static方法,也没有任何可用的field。
Example:
????????????????
?
/*?This?class?is?unusable,?since?it?cannot?be
?instantiated?(private?constructor),
?and?no?static?method?can?be?called.
?*/
public?class?Foo?{
?private?Foo()?{}
?void?foo()?{}
}
???????????
块级别的同步可以确保内含真正需要同步的代码。?????
Example:
????????????????
?
public?class?Foo?{
?//?Try?to?avoid?this
?synchronized?void?foo()?{
?}
?//?Prefer?this:
?void?bar()?{
??synchronized(this)?{
??}
?}
}
为了保证所有监听线程有均等的机会????????????
Example:
????????????????
?
public?class?Foo?{
?void?bar()?{
??x.notify();
??//?If?many?threads?are?monitoring?x,?only?one?(and?you?won't?know?which)?will?be?notified.
??//?use?instead:
??x.notifyAll();
?}
}
每个产生的异常类型都应该在自己的catch块中被处理?
?????????????
Example:
????????????????
?
try?{?//?Avoid?this
?//?do?something
}?catch?(Exception?ee)?{
?if?(ee?instanceof?IOException)?{
??cleanup();
?}
}
try?{??//?Prefer?this:
?//?do?something
}?catch?(IOException?ee)?{
?cleanup();
}
?
???????
当给予一个null作为参数时,instanceof返回false??
Example:
????????????????
??????
class?Foo?{
?void?bar(Object?x)?{
??if?(x?!=?null?&&?x?instanceof?Bar)?{
???//?just?drop?the?"x?!=?null"?check
??}
?}
}??????
?
Example:
????????????????
?
class?Foo?{
?boolean?bar(String?a,?String?b)?{
??return?a?==?b;
?}
}
?
?
??
???????????
Example:
?
class?Foo?{
?boolean?bar(String?x)?{
??return?x.equals("2");?//?should?be?"2".equals(x)
?}
}
避免创建不必要的本地变量,不仅在return的场合需要注意这一点
Example:
??????????????
??public?class?Foo?{
????public?int?foo()?{
??????int?x?=?doSomething();
??????return?x;??//?instead,?just?'return?doSomething();'
????}
??}
??
??????
???????????
Example:
????????????????
private?static?Foo?foo?=?null;
?
//multiple?simultaneous?callers?may?see?partially?initialized?objects
public?static?Foo?getFoo()?{
????if?(foo==null)
????????foo?=?new?Foo();
????return?foo;
}
?????
接口只应该是对行为建模????
???????
Example:
????????????????
????
????public?interface?ConstantsInterface?{
?????public?static?final?int?CONSTANT1=0;
?????public?static?final?String?CONSTANT2="1";
????}
????
??????
???????????
SimpleDateFormat是非同步的。Sun公司建议对每个线程单独的format实例。如果多线程必须访问一个静态formatter,formatter必须在方法或块级别同步。
代码示例:
????????????????
????
public?class?Foo?{
????private?static?final?SimpleDateFormat?sdf?=?new?SimpleDateFormat();
????void?bar()?{
????????sdf.format();?//?bad
????}
????synchronized?void?foo()?{
????????sdf.format();?//?good
????}
}
????
??????
???????????
在一个catch块中抛出一个新的异常却不把原始的异常传递给新的异常会导致真正的追踪信息栈丢失,而且导致难以有效的调试。?
代码示例:?
public?class?Foo?{
????void?good()?{
????????try{
????????????Integer.parseInt("a");
????????}?catch(Exception?e){
????????????throw?new?Exception(e);
????????}
????}
????void?bad()?{
????????try{
????????????Integer.parseInt("a");
????????}?catch(Exception?e){
????????????throw?new?Exception(e.getMessage());
????????}
????}
}
????
??????
???????????
java.util.Collection类的isEmpty方法提供判断一个集合类是否包含元素。不要是使用size()和0比较来重复类库已经提供的方法。?这条原则告诉我们一个普遍的原则:复用。尽量复用,充分利用已有的资源,不要重复自己(DRY)。比如apache提供了大量工具类供我们使用,我们没有必要再自己写了。
代码示例:????????????????
????
????public?class?Foo?{
????????void?good()?{
????????????List?foo?=?getList();
????????????if?(foo.isEmpty())?{
????????????????//?blah
????????????}
????????}
?
????????void?bad()?{
????????????List?foo?=?getList();
????????????????if?(foo.size()?==?0)?{
????????????????????//?blah
????????????????}
????????????}
????}
????
??????
???????????
一个类只包含私有的构造器应该是final的,除非私有构造器被一个内部类访问。?
????????????????
public?class?Foo?{??//Should?be?final
????private?Foo()?{?}
}
?????
???????????
一个抽象类中的空方法也应该是抽象的,因为开发者有可能会信任这个空的实现而不去编写恰当的代码。?
Example:
????????????????
????????????
????????????????public?abstract?class?ShouldBeAbstract
????????????????{
????????????????????public?Object?couldBeAbstract()
????????????????????{
????????????????????//?Should?be?abstract?method??
????????????????????return?null;
????????????????????}
?
????????????????????public?void?couldBeAbstract()
????????????????????{
????????????????????}
????????????????}
域变量只在一个方法中被使用并且第一次使用时对这个域赋值。这种域可以改写为本地变量。?
Example:
????????????????
public?class?Foo?{
????private?int?x;??//Why?bother?saving?this?
????public?void?foo(int?y)?{
?????x?=?y?+?5;
?????return?x;
????}
}
???
???????????
对于任何返回数组的方法,返回一个空的数组是一个比返回null引用更好的做法。?
Example:
????????????public?class?Example
????????????{
????????????????//?Not?a?good?idea...
????????????????public?int?[]badBehavior()
????????????????{
????????????????????//?...
????????????????????return?null;
????????????????}
?
????????????????//?Good?behavior
????????????????public?String[]?bonnePratique()
????????????????{
????????????????????//...
????????????????????return?new?String[0];
????????????????}
????????????}
如果抽象类没有提供任何的方法,它可能只是一个不可被实例化的数据容器,在这种状况下,更好的方法是使用私有的或受保护的构造器以阻止实例化可以让类避免带有欺骗性的抽象。?这条原则也适用于普通的数据容器类,比如我们常用的常量类,如果是常量类,那么请提供私有的或受保护的构造器。
Example:
???
public?class?abstract?Example?{
????String?field;
????int?otherField;
}
声明以及捕获异常的指导原则
捕获Throwable意味着不能处理的异常(错误)你也想处理,比如OutOfMemoryError.
示例代码:
????????????????
????????????????
public?class?Foo?{
?public?void?bar()?{
??try?{
???//?do?something
??}?catch?(Throwable?th)?{??//Should?not?catch?throwable
???th.printStackTrace();
??}
?}
}
????????????????
??????
???????????
不要在方法签名处?throws?Exception,除了增加调用者的反感外,没看到有什么实际的好处。正确的做法是要么抛出明确的checked?exception要么抛出RuntimeException。Spring框架所有方法都只抛出RuntimeException,这样方便用户对异常的处理,很值得我们借鉴。
示例代码:
????????????????
????????????????
public?void?methodThrowingException()?throws?Exception?{
}
????????????????
??????
???????????
这样做会产生类似GOTO语句的效果,增加代码理解的难度。
示例代码:
????????????????
??
public?class?Foo?{
?void?bar()?{
??try?{
???try?{
???}?catch?(Exception?e)?{
????throw?new?WrapperException(e);
????//?this?is?essentially?a?GOTO?to?the?WrapperException?catch?block
???}
??}?catch?(WrapperException?e)?{
???//?do?some?more?stuff
??}
?}
}
除非你想把真正的错误掩盖掉。?
示例代码:
??????????????????
public?class?Foo?{
?void?bar()?{
??try?{
???//?do?something
???}??catch?(NullPointerException?npe)?{
??}
?}
}
?
?????????
用户总是会以为NullPointerException应该是由JVM抛出的。??????????????
示例代码:
????????????????
????????
public?class?Foo?{
?void?bar()?{
??throw?new?NullPointerException();
?}
}
??
??????
???????????
人们会怀疑你捕获它的目的?
示例代码:
??????????????????
??public?class?Foo?{
???void?bar()?{
????try?{
????//?do?something
????}??catch?(SomeException?se)?{
???????throw?se;
????}
???}
??}
??
????
???????????
Errors是系统级别的异常,我们不要扩展他们。??????????
?示例代码:
????????????????
????????public?class?Foo?extends?Error?{?}
????
???????????
这样做会让人感到困惑,还可能掩盖代码的异常或者缺陷,也使代码的清理部分变得不可靠。
示例代码:
????????????????
????????????
????????????????public?class?Foo?
????????????????{
????????????????????public?void?bar()
????????????????????{
????????????????????????try?{
????????????????????????????//?Here?do?some?stuff
????????????????????????}
????????????????????????catch(?Exception?e)?{
????????????????????????????//?Handling?the?issue
????????????????????????}
????????????????????????finally?
????????????????????????{
????????????????????????????//?is?this?really?a?good?idea??
????????????????????????????throw?new?Exception();
????????????????????????}
????????????????????}
????????????????}
????????????
????????
???????????
不管你信不信,我是真的看到过这样的代码。
实例代码:
??????????????????
????public?class?Foo?{
?????void?bar()?{
??????try?{
???????//?do?something
??????}??catch?(SomeException?se)?{
?????????//?harmless?comment??????
???????????throw?new?SomeException(se);
??????}
?????}
????}
?
就一个原则:没有使用的就去掉,保持代码的干净、整洁。
没有使用的代码包括:
?
如果代码中包含多个重复的字符串,那么定义一个字符串常量来代替它。
示例代码:
public?class?Foo?{
?private?void?bar()?{
????buz("Howdy");
????buz("Howdy");
????buz("Howdy");
????buz("Howdy");
?}
?private?void?buz(String?x)?{}
}
?
????
???????????
通常情况下,这么做没有用处,只会破坏字符串的享元策略。
示例代码:
????????????????
?
public?class?Foo?{
?private?String?bar?=?new?String("bar");?//?just?do?a?String?bar?=?"bar";
}
?
????
???????????
基本没人会这么做的。
示例代码:
????????????????
?
public?class?Foo?{
?private?String?baz()?{
??String?bar?=?"howdy";
??return?bar.toString();
?}
}
??
equalsIgnoreCase()?比?toUpperCase/toLowerCase().equals()更快。
示例:???????????
?public?class?Foo?{
??public?boolean?bar(String?buz)?{
????//?should?be?buz.equalsIgnoreCase("baz")
????return?buz.toUpperCase().equals("baz");
????//?another?unnecessary?toUpperCase()
????//?return?buz.toUpperCase().equalsIgnoreCase("baz");
??}
?}
?????????????????
???????
???????????
示例代码:
????????????????
??
public?class?Foo?{
?void?bar()?{
??StringBuffer?sb?=?new?StringBuffer();
??//?this?is?bad
??if(sb.toString().equals(""))?{}
??//?this?is?good
??if(sb.length()?==?0)?{}
?}
}
???
比如String.indexOf('a')比String.indexOf("a")快,StringBuilder.append('a')比StringBuilder.append("a")快
示例代码:
public?class?Foo?{
?void?bar()?{
??String?s?=?"hello?world";
??//?avoid?this
??if?(s.indexOf("d")?{}
??//?instead?do?this
??if?(s.indexOf('d')?{}
?}
}
???????????
不指定,则默认长度是16,这样当长度不够时,就会有扩容的动作了。
示例代码:
????????????????
?
public?class?Foo?{
????void?bar()?{
????????StringBuffer?bad?=?new?StringBuffer();
????????bad.append("This?is?a?long?string,?will?exceed?the?default?16?characters");//bad
????????StringBuffer?good?=?new?StringBuffer(41);
????????good.append("This?is?a?long?string,?which?is?pre-sized");//good
????}
}
?
????
???????????
示例代码:
public?String?convert(int?i)?{
??String?s;
??s?=?"a"?+?String.valueOf(i);?//?Bad
??s?=?"a"?+?i;?//?Better
??return?s;
}
?
??????????
???????????
示例代码:
????????????????
?
class?Foo?{
??StringBuffer?sb1?=?new?StringBuffer('c');?//Bad
??StringBuffer?sb2?=?new?StringBuffer("c");?//Better
}
?
????
???????????
??
示例代码:
class?Foo?{
??boolean?test(String?s)?{
????if?(s?==?"one")?return?true;?//Bad
????if?("two".equals(s))?return?true;?//Better
????return?false;
??}
}
?
????
???????????
?
???????????
Example:
????????????????
?
class?Foo?{
????private?StringBuffer?memoryLeak;
}
性能优化方面的一些最佳实践
示例代码:
public?class?Bar?{
?public?void?foo?()?{
??String?a?=?"a";?//if?a?will?not?be?assigned?again?it?is?better?to?do?this:
??final?String?b?=?"b";
?}
}
示例代码:
????????????????
??
public?void?foo?(String?param)?{
??//?do?stuff?with?param?never?assigning?it
??//?better:?public?void?foo?(final?String?param)?{
}
??
??????
???????????
示例代码:
????????????????
?
public?class?Something?{
??public?static?void?main(?String?as[]?)?{??
????for?(int?i?=?0;?i?<?10;?i++)?{
??????Foo?f?=?new?Foo();?//Avoid?this?whenever?you?can?it's?really?expensive
????}
??}
}
?
????
???????????
示例代码:
????????????????
?
public?class?SimpleTest?extends?TestCase?{
?public?void?testX()?{
??Collection?c?=?new?Vector();
??//?This?achieves?the?same?with?much?better?performance
??//?Collection?c?=?new?ArrayList();
?}
}
如果你的程序对性能要求很苛刻,那么可以考虑使用String.charAt(0)==x?来代替String.startWith?
???????????
示例代码:
????????????????
??
public?class?Foo?{
??boolean?checkIt(String?x)?{
??????return?x.startsWith("a");
??}
}
?
??????
???????????
这个规则目前不靠谱,因为JDK5以上的版本已经对“+”进行了优化。
示例代码:
????????????????
??????
public?class?Foo?{
?void?bar()?{
??String?a;
??a?=?"foo";
??a?+=?"?bar";
??//?better?would?be:
??//?StringBuffer?a?=?new?StringBuffer("foo");
??//?a.append("?bar);
?}
}
??????
???????????
???????????
??????
示例代码:
????????????????
???
???public?class?Test?{
????public?void?foo(Integer[]?ints)?{
????//?could?just?use?Arrays.asList(ints)
?????List?l=?new?ArrayList(10);
?????for?(int?i=0;?i<?100;?i++)?{
??????l.add(ints[i]);
?????}
?????for?(int?i=0;?i<?100;?i++)?{
??????l.add(a[i].toString());?//?won't?trigger?the?rule
?????}
????}
???}
???
示例代码:
public?class?Test?{
?public?void?bar()?{
??int[]?a?=?new?int[10];
??int[]?b?=?new?int[10];
??for?(int?i=0;i<10;i++)?{
???b[i]=a[i];
??}
?}
}
????????????//?this?will?trigger?the?rule
????????????for?(int?i=0;i<10;i++)?{
?????????????b[i]=a[c[i]];
????????????}
?
????????}
????}
????
Integer的各种解析方法应该直接调用。
示例代码:
????????????????
?
public?int?convert(String?s)?{
??int?i,?i2;
?
??i?=?Integer.valueOf(s).intValue();?//?this?wastes?an?object
??i?=?Integer.parseInt(s);?//?this?is?better
?
??i2?=?Integer.valueOf(i).intValue();?//?this?wastes?an?object
??i2?=?i;?//?this?is?better
?
??String?s3?=?Integer.valueOf(i2).toString();?//?this?wastes?an?object
??s3?=?Integer.toString(i2);?//?this?is?better
?
??return?i2;
}
?
示例代码:?????
????????String?s?=?""?+?123;?//?bad?
????????String?t?=?Integer.toString(456);?//?ok?
???????????
人人都要遵守
空Catch,空If,空while,空try,空finally,空switch,空Synchronized块,空static块
?