問題のありそうなロジックを検出するルールセットです。
不必要なコンストラクタ宣言を検出します。
public class Foo {
public Foo() {}
}
変数宣言文以外でのnull値の代入を検出します。
Object x = null; // これはOK x = new Object(); x = null; // これはNG
一般的に、これは悪い形式のコーディングだとされています。
昔の記事にはよく、
「明示的にnullにしないとガーベッジコレクト(以下GC)されないのでnullを代入する事」
などという事が書いてありましたが、これは一般的には
ロジックそのものに何らかの間違いがある事を意味しています。
ただし、一部のソートロジックでは明示的なnull値の代入が
GCの効率を上げるために有用である事もあります。
その事に自信があるのなら、この警告を無視しても構わないでしょう。
メソッドの最後以外にreturn文があるロジックを検出します。
つまりこのルールは、メソッドの最後に唯一のreturn文がある事を期待します。
public void foo(int x) {
if (x > 0) {
return "hey"; // メソッドの途中にあるreturn文
}
return "hi";
}
不必要な識別子の記述を検出します。
public interface Foo {
public abstract void bar(); // public abstract は必要無い
public static final int X = 0; // public static final は必要無い
}
オペランド中の代入ロジックを検出します。
if ((x = getX()) == 10) { // 読みにくいので止めた方がいい
...
}
コンストラクタが一つも定義されていないクラスを検出します。
この場合、クラスには引数無のデフォルトコンストラクタが作成されますが
これに頼ったコーディングは、思わぬところで弊害を引き起こす可能性があります。
sun. で始まるimport文を検出します。
これらは通常、明示的にソースに記述すべきではありません。
疑わしい8進数表記を検出します。
s = "\123"; // これは "\123" と見なされる s = "\128"; // これは "\12" + "8" と見なされる(8進数に8は使えない為)
コンストラクタ内で super または this が呼び出されていないロジックを検出します。
public Foo() {
this.cnt = 10; // これはNG
}
public Foo() {
super(); // これはOK
}
public Foo() {
this(10); // これもOK
}
不必要な括弧を検出します。
return (true); // この括弧は不必要
1箇所からしか使用されていないフィールドを検出します。
通常、これはローカル変数化できます。
private int x; // このフィールドは1箇所からしか使われていない
public void foo(int y) {
x = y + 5;
return x;
}
アクセス識別子を指定していない箇所を検出します。
この場合、パッケージprivateとなります。これはあまり推奨されません。
public class Foo {
int bar; // アクセス識別子が指定されていない
}
最適化されていないBoolean値の反転ロジックを検出します。
b = !b; // これは以下のようにする b ^= true; // …いや、まぁ確かに。でも正直言ってわかりにくいと思いません?
不自然なデータフローを検出します。
{
int buz = 5; // この値はどこからも使われていない
buz = 6;
foo(buz);
buz = 2; // buzへ代入しているが、以降どこからも参照されていない
}
一つのクラスで検出する最大警告数を制限します。
デフォルト値は100です。
一つのメソッドでチェックする最大パス数を制限します。
デフォルト値は1000です。
この値を小さくするとパフォーマンスは上がりますが、検出できる数も減ります。
final のローカル変数を検出します。
public void foo() {
final String finalLocalVariable;
}
Javaの言語仕様上、無名クラスから参照可能にするために
ローカル変数を final にすることはよくありますが、これは良くないとされているようです。
short 型の変数定義を検出します。
これもJavaの言語仕様に対してなかなか挑戦的なチェックです。
PMDのサイトによれば、short は int に比べてメモリ量の節約にはなるが
(int は4バイト、shortは2バイト)
shortを計算するときには一旦intに変換してまたshortに変換するという
ロジックが走り、結局intより多くのメモリ量を使うことになると主張しています。
確かに、メモリ節約という理由だけでshortを使うのはあまり良いことではないと僕も思います。
volatile キーワードの使用を検出します。
詳しい理由はわかりませんが、volatileキーワードの安易な使用は
控えるべきだという主張のようです。
JDK5以降は concurrent というマルチスレッドに対応するパッケージが用意されていますから
これを使った方がいいということなのでしょう。
System.loadLibrary メソッドの使用を検出します。
これはネイティブ関数を使うためのものですが、
プラットフォーム非依存というJavaのメリットを消してしまいます。
AccessibleObject.setAccessible などを
PrivilegedAction 外で呼び出している箇所を検出します。
System.gc(), Runtime.getRuntime().gc(), System.runFinalization() の
呼び出しを検出します。