PMD Javaルール Design

PMDのJavaルールについてまとめます。バージョン6.35.0時のルールとなっています。
非推奨となっているルールには「△」を先頭に付与しています。

バージョン6.35.0から6.47.0までのルールの差分については別の記事でまとめています。 olafnosuke.hatenablog.com

Designカテゴリには、設計上の問題を発見するのに役立つルールが含まれている。

AbstractClassWithoutAnyMethod

抽象クラスにメソッドがない

// NG
public abstract class Animal {
    private String name;
}

// OK
public abstract class Animal {
    private String name;
    
    abstract void doSomething();
}

ルール設定例

<rule ref="category/java/design.xml/AbstractClassWithoutAnyMethod" />

AvoidCatchingGenericException

NullPointerException、RuntimeException、Exceptionのキャッチを避ける

// NG
try {
} catch (NullPointerException e) {
} catch (RuntimeException e) {
} catch (Exception e) {
}

ルール設定例

<rule ref="category/java/design.xml/AvoidCatchingGenericException" />

AvoidDeeplyNestedIfStmts

深過ぎるif文のネストはしない

// NG
int x = 1;
int y = 2;
int z = 3;
if (x > y) {
    if (y > z) {
        if (z == x) {
        }
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
problemDepth 3 if文のネストの閾値 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/AvoidDeeplyNestedIfStmts" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/AvoidDeeplyNestedIfStmts">
    <properties>
        <property name="problemDepth" value="3" />
    </properties>
</rule>

AvoidRethrowingException

キャッチされた例外を単に再スローしない

// NG
try {
} catch (RuntimeException e) {
    throw e;
} 

ルール設定例

<rule ref="category/java/design.xml/AvoidRethrowingException" />

AvoidThrowingNewInstanceOfSameException

キャッチされた例外と同じ型の新しいインスタンス単を再スローしない

// NG
try {
} catch (RuntimeException e) {
    throw new RuntimeException(e);
} 

ルール設定例

<rule ref="category/java/design.xml/AvoidThrowingNewInstanceOfSameException" />

AvoidThrowingNullPointerException

NullPointerExceptionを手動でスローしない

// NG
void doSomething() {
    throw new NullPointerException();
}

ルール設定例

<rule ref="category/java/design.xml/AvoidThrowingNullPointerException" />

AvoidThrowingRawExceptionTypes

RuntimeException、Throwable、Exception、Errorをthrowしない

// NG
void doSomething() {
    throw new RuntimeException();
}

ルール設定例

<rule ref="category/java/design.xml/AvoidThrowingRawExceptionTypes" />

AvoidUncheckedExceptionsInSignatures

メソッド、コンストラクターのthrows句で非検査例外を明示的に宣言しない

// NG
void doSomething() throws RuntimeException {
}

ルール設定例

<rule ref="category/java/design.xml/AvoidUncheckedExceptionsInSignatures" />

ClassWithOnlyPrivateConstructorsShouldBeFinal

プライベートコンストラクターのみを持つクラスは final で宣言する

// NG
public class Animal {
    private Animal() {
    }
}

// OK
public final class Animal {
    private Animal() {
    }
}

ルール設定例

<rule ref="category/java/design.xml/ClassWithOnlyPrivateConstructorsShouldBeFinal" />

CognitiveComplexity

1 つのメソッド内にあまりにも多くのロジックを含め過ぎない
人間がメソッドを読んで理解することがどれだけ難しいかを示す指標。
制御フローが入れ子になっているとメソッドを理解するのが難しくなるため、制御フローが入れ子になるたびに認知的複雑さが増す。
CognitiveComplexityとは

// if文やループの処理が増えるほど複雑になりすぎる
void doSomething() {
    for (int i = 0; i < 10; i++) {           // +1
        for (int j = 10; j < 20; j++) {      // +1
            if (i < 5) {                     // +2
            } else if (j < 15) {             // +2
            } else if (i == 9 && j == 19) {  // +2
            } else {                         // +2
            }                                
        }
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
reportLevel 15 複雑さの尺度の検知される閾値 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/CognitiveComplexity" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/CognitiveComplexity">
    <properties>
        <property name="reportLevel" value="15" />
    </properties>
</rule>

CollapsibleIfStatements

条件式を&&で結合できる二重のifステートメントがないか

// NG
int a = 1;
int b = 2;
if (a < 1) {
    if (b < 2) {
    }
}

// OK
int a = 1;
int b = 2;
if(a < 1 && b < 2){
}

ルール設定例

<rule ref="category/java/design.xml/CollapsibleIfStatements" />

CouplingBetweenObjects

ひとつのオブジェクトの中で使用しているフィールド、ローカル変数、返却値のクラス種類が多すぎないか

プロパティ

名前 デフォルト値 説明 複数指定
threshold 20 型数の閾値 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/CouplingBetweenObjects" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/CouplingBetweenObjects">
    <properties>
        <property name="threshold" value="20" />
    </properties>
</rule>

CyclomaticComplexity

メソッドを複雑にしすぎない
メソッド内の決定点の数を数え、メソッドのエントリに1を加えてメソッドの複雑さを評価する。
決定点とは、制御フローがプログラム内の別の場所にジャンプする場所で、if、while、for、case などのすべての制御フロー文が含まれる。
CyclomaticComplexityとは

プロパティ

名前 デフォルト値 説明 複数指定
classReportLevel 80 クラスの複雑度の検出閾値 -
methodReportLevel 10 メソッドの複雑度の検出閾値 -
cycloOptions Cycloの計算のオプション 「|」区切り

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/CyclomaticComplexity" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/CyclomaticComplexity">
    <properties>
        <property name="classReportLevel" value="80" />
        <property name="methodReportLevel" value="10" />
        <property name="cycloOptions" value="" />
    </properties>
</rule>

DataClass

データクラスかどうか
データクラス:複雑な機能を持たないシンプルなデータホルダー
データクラスはその内部を直接公開することで、カプセル化を破壊し、システムの保守性や理解性を低下させる

//NG
public class Animal {
    public String name = "";
    public int age = 0;
    public int weight = 0;

    private int hight = 0;

    public void setHight(int hight) {
        this.hight = hight;
    }
}

ルール設定例

<rule ref="category/java/design.xml/DataClass" />

DoNotExtendJavaLangError

java.lang.Error をextendしたクラスは定義しない

// NG
public class SampleError extends Error {
}

ルール設定例

<rule ref="category/java/design.xml/DoNotExtendJavaLangError" />

ExceptionAsFlowControl

例外のスローを複雑にしない

// NG
try {
    try {
    } catch (IllegalArgumentException e) {
        throw new RuntimeException(e);
    }
} catch (RuntimeException e) {
}

ルール設定例

<rule ref="category/java/design.xml/ExceptionAsFlowControl" />

ExcessiveClassLength

行数が長過ぎるクラスがないか
デフォルトでは1000行を超えると検知される

プロパティ

名前 デフォルト値 説明 複数指定
minimum 1000.0 行数の最大値 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/ExcessiveClassLength" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/ExcessiveClassLength">
    <properties>
        <property name="minimum" value="1000.0" />
    </properties>
</rule>

ExcessiveImports

インポートが多過ぎるクラスがないか
デフォルトでは30以上で検知される

プロパティ

名前 デフォルト値 説明 複数指定
minimum 30.0 インポートの最大値 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/ExcessiveImports" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/ExcessiveImports">
    <properties>
        <property name="minimum" value="30.0" />
    </properties>
</rule>

ExcessiveMethodLength

行数が長すぎるメソッドがないか
デフォルトでは100行を超えると検知される

プロパティ

名前 デフォルト値 説明 複数指定
minimum 100.0 行数の最大値 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/ExcessiveMethodLength" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/ExcessiveMethodLength">
    <properties>
        <property name="minimum" value="100.0" />
    </properties>
</rule>

ExcessiveParameterList

メソッドのパラメータ数が多いものがないか
デフォルトでは10以上で検知される

// NG
void doSomething(int i, int a, int b, int c, int d, int e, int f, int g, int h, int j) {
}

プロパティ

名前 デフォルト値 説明 複数指定
minimum 10.0 パラメータ数の最大値 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/ExcessiveParameterList" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/ExcessiveParameterList">
    <properties>
        <property name="minimum" value="10.0" />
    </properties>
</rule>

ExcessivePublicCount

多くのpublicメソッド・フィールドが定義されているクラスがないか
デフォルトでは45以上で検知される

プロパティ

名前 デフォルト値 説明 複数指定
minimum 45.0 メソッド・フィールド数の最大値 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/ExcessivePublicCount" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/ExcessivePublicCount">
    <properties>
        <property name="minimum" value="45.0" />
    </properties>
</rule>

FinalFieldCouldBeStatic

finalフィールドはstaticにする

// NG
public final int BAR = 42;

ルール設定例

<rule ref="category/java/design.xml/FinalFieldCouldBeStatic" />

GodClass

ゴッドクラスとなっていないか
ゴッドクラスとは

ルール設定例

<rule ref="category/java/design.xml/GodClass" />

ImmutableField

finalで宣言されていない不変なフィールドがないか

// NG
public class Sample {

    private int number;

    public Sample() {
        number = 3;
    }

    int doSomething() {
        return number + 2;
    }

}

プロパティ

名前 デフォルト値 説明 複数指定
ignoredAnnotations lombok.Setter| lombok.Getter| lombok.Builder| lombok.Data| lombok.RequiredArgsConstructor| lombok.AllArgsConstructor| lombok.Value| lombok.NoArgsConstructor このルールで無視するアノテーションの完全修飾名 「|」区切り

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/ImmutableField" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/ImmutableField">
    <properties>
        <property name="ignoredAnnotations" value="lombok.Setter|lombok.Getter|lombok.Builder|lombok.Data|lombok.RequiredArgsConstructor|lombok.AllArgsConstructor|lombok.Value|lombok.NoArgsConstructor" />
    </properties>
</rule>

LawOfDemeter

デメテルの法則に則っているか
デメテルの法則

ルール設定例

<rule ref="category/java/design.xml/LawOfDemeter" />

LogicInversion

式全体を否定するのではなくて反対の演算子を使う

// NG
int a = 1;
int b = 2;
if (!(a == b)) { 
}

// OK
int a = 1;
int b = 2;
if (a != b) { 
}

ルール設定例

<rule ref="category/java/design.xml/LogicInversion" />

LoosePackageCoupling

指定したパッケージ配下にある許可していないクラスを使用していないか
このルールを適用するためには必ず設定が必要。

<!-- 以下の設定の場合org.springframework.util配下はDigestUtilsのみ使用可能 -->
<rule ref="category/java/design.xml/LoosePackageCoupling">
    <properties>
        <property name="packages" value="org.springframework.util" />
        <property name="classes" value="DigestUtils" />
    </properties>
</rule>
// NG
import org.springframework.util.StringUtils;

public class Sample {
    void doSomething() {
        StringUtils.split("", "");
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
packages 制限をつけるパッケージ 「,」区切り
classes 使用を許可するクラス 「,」区切り

ルール設定例

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/LoosePackageCoupling">
    <properties>
        <property name="packages" value="" />
        <property name="classes" value="" />
    </properties>
</rule>

△ ModifiedCyclomaticComplexity

非推奨のため省略


MutableStaticState

プライベートでないstaticフィールドはfinal と宣言して定数 (または不変参照) にする必要がある

// NG
public static Book book = new Book();

// OK
public static final Book book = new Book();

ルール設定例

<rule ref="category/java/design.xml/MutableStaticState" />

△ NcssConstructorCount

非推奨のため省略


NcssCount

コメント、空白行を無視し、実際のステートメントのみの行数をカウント
NCSSの計算方法

プロパティ

名前 デフォルト値 説明 複数指定
methodReportLevel 60 NCSSで計算したメソッドの行数の閾値 -
classReportLevel 1500 NCSSで計算したクラスの行数の閾値 -
ncssOptions 1500 Ncss の計算のオプション 「|」区切り

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/NcssCount" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/NcssCount">
    <properties>
        <property name="methodReportLevel" value="60" />
        <property name="classReportLevel" value="1500" />
        <property name="ncssOptions" value="" />
    </properties>
</rule>

△ NcssMethodCount

非推奨のため省略


△ NcssTypeCount

非推奨のため省略


NPathComplexity

NPath値を測定し、複雑なメソッドがないか
NPath値の計算

プロパティ

名前 デフォルト値 説明 複数指定
reportLevel 200 NPath値の閾値 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/NPathComplexity" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/NPathComplexity">
    <properties>
        <property name="reportLevel" value="200" />
    </properties>
</rule>

SignatureDeclareThrowsException

Exceptionをスローするメソッドを検出

// NG
// もっと具体的な例外を記述するべき
void doSomething() throws Exception {
}

プロパティ

名前 デフォルト値 説明 複数指定
IgnoreJUnitCompletely false JUnitのすべてのメソッドが例外をスローできるようにする -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/SignatureDeclareThrowsException" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/SignatureDeclareThrowsException">
    <properties>
        <property name="IgnoreJUnitCompletely" value="false" />
    </properties>
</rule>

SimplifiedTernary

三項演算子でなくても記述できるところを検出

// NG
public boolean doSomething() {
    boolean condition = true;
    return condition ? true : something(); 
}

// OK
public boolean doSomething() {
    boolean condition = true;
    return condition || something();
}

ルール設定例

<rule ref="category/java/design.xml/SimplifiedTernary" />

SimplifyBooleanAssertion

assertTrue または assertFalse テストでの否定を避ける

// NG
@Test
void test() {
    boolean b = false;
    assertTrue(!b);
}

// OK
@Test
void test() {
    boolean b = false;
    assertFalse(b);
}

ルール設定例

<rule ref="category/java/design.xml/SimplifyBooleanAssertion" />

SimplifyBooleanExpressions

ブール式での不必要な比較を避ける

// NG
public class Sample {
    private boolean b = (isExist() == true);

    private boolean isExist() {
        return false;
    }
}

// OK
public class Sample {
    private boolean b = isExist();

    private boolean isExist() {
        return false;
    }
}

ルール設定例

<rule ref="category/java/design.xml/SimplifyBooleanExpressions" />

SimplifyBooleanReturns

booleanを返却するためだけにif..elseステートメントを使わない

// NG
private boolean isExist() {
    int x = 2;
    int y = 5;
    if (x == y) {
        return true;
    } else {
        return false;
    }
}

// OK
private boolean isExist() {
    int x = 2;
    int y = 5;
    return x == y;
}

ルール設定例

<rule ref="category/java/design.xml/SimplifyBooleanReturns" />

SimplifyConditional

instanceofの前に不要なnullチェックがないか

// NG
void doSomething() {
   String x = "abc";
   if (x != null && x instanceof String) {
   }
}

// OK
void doSomething() {
   String x = "abc";
   if (x instanceof String) {
   }
}

ルール設定例

<rule ref="category/java/design.xml/SimplifyConditional" />

SingularField

1つのメソッドからしか使用されていないフィールドがないか

// NG
public class Sample {
    private String x;

    void doSomething(String y) {
        x = y;
    }
}

// OK
public class Sample {
    void doSomething(String y) {
        String x = y; // ローカル変数にするべき
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
ignoredAnnotations lombok.Setter| lombok.Getter| lombok.Builder| lombok.Data| lombok.RequiredArgsConstructor| lombok.AllArgsConstructor| lombok.Value| lombok.NoArgsConstructor| lombok.experimental.Delegate| lombok.EqualsAndHashCode このルールで無視するアノテーションのの完全修飾名 「|」区切り
checkInnerClasses false 内部クラスを確認するか -
disallowNotAssignment false 最初の使用がアサインメントでない場合、違反を認めない -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/SingularField" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/SingularField">
    <properties>
        <property name="ignoredAnnotations" value="lombok.Setter|lombok.Getter|lombok.Builder|lombok.Data|lombok.RequiredArgsConstructor|lombok.AllArgsConstructor|lombok.Value|lombok.NoArgsConstructor|lombok.experimental.Delegate|lombok.EqualsAndHashCode" />
        <property name="checkInnerClasses" value="false" />
        <property name="disallowNotAssignment" value="false" />
    </properties>
</rule>

△ StdCyclomaticComplexity

非推奨のため省略


SwitchDensity

switchのケースに対する処理が多すぎないか

プロパティ

名前 デフォルト値 説明 複数指定
minimum 10.0 caseの処理(ステートメント)の最大値 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/SwitchDensity" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/SwitchDensity">
    <properties>
        <property name="minimum" value="10.0" />
    </properties>
</rule>

TooManyFields

フィールドが多すぎないか

プロパティ

名前 デフォルト値 説明 複数指定
maxfields 15 最大許容フィールド数 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/TooManyFields" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/TooManyFields">
    <properties>
        <property name="maxfields" value="15" />
    </properties>
</rule>

TooManyMethods

メソッドが多すぎないか

プロパティ

名前 デフォルト値 説明 複数指定
maxmethods 10 最大許容メソッド数 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/TooManyMethods" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/TooManyMethods">
    <properties>
        <property name="maxmethods" value="10" />
    </properties>
</rule>

UselessOverridingMethod

オーバーライドするメソッドがスーパークラスで定義された同じメソッドを呼び出すだけになっていないか

// NG
public String toString() {
    return super.toString();
}

プロパティ

名前 デフォルト値 説明 複数指定
ignoreAnnotations false アノテーションを無視する -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/UselessOverridingMethod" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/UselessOverridingMethod">
    <properties>
        <property name="ignoreAnnotations" value="false" />
    </properties>
</rule>

UseObjectForClearerAPI

publicメソッドで多くの情報を複数の引数として渡す場合、それらすべての情報を表すためにオブジェクトを使用するべき

// NG
// 4つの引数をまとめられるクラスを作るべき
public void connect(String username,
       String pssd,
       String databaseName,
       String databaseAdress){
}

ルール設定例

<rule ref="category/java/design.xml/UseObjectForClearerAPI" />

UseUtilityClass

staticメソッドしか持たないクラスはユーティリティクラスにすること検討するべき

// NG
// ユーティリティクラスとする場合はprivateのコンストラクタを定義する
public class Sample {
    static void doSomething() {
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
ignoredAnnotations lombok.experimental.UtilityClass このルールで無視するアノテーションの完全修飾名 「|」区切り

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/design.xml/UseUtilityClass" />

<!-- プロパティ設定あり -->
<rule ref="category/java/design.xml/UseUtilityClass">
    <properties>
        <property name="ignoredAnnotations" value="lombok.experimental.UtilityClass" />
    </properties>
</rule>

他のカテゴリのルールもまとめています。

Best Practiceカテゴリのまとめはこちら: olafnosuke.hatenablog.com

Code Styleカテゴリのまとめはこちら: olafnosuke.hatenablog.com

Documentationカテゴリのまとめはこちら: olafnosuke.hatenablog.com

Error Proneカテゴリのまとめはこちら: olafnosuke.hatenablog.com

Multithreadingカテゴリのまとめはこちら: olafnosuke.hatenablog.com

Performanceカテゴリのまとめはこちら: olafnosuke.hatenablog.com

Securityカテゴリのまとめはこちら: olafnosuke.hatenablog.com