PMDバージョン: 7.13.0
CheckResultSet
公式ドキュメント: CheckResultSet
Since: PMD 4.1
Priority: Medium (3)
Description:
ResultSet
のナビゲーションメソッド(next
、previous
、first
、last
)の戻り値を常に確認する必要があります。戻り値がfalseの場合、適切に処理しないと例外が発生する可能性があります。
Configuration:
<rule ref="category/java/bestpractices.xml/CheckResultSet" />
Example:
// NG:next() の戻り値を確認せずに値を取得 ResultSet rs = stmt.executeQuery("SELECT * FROM users"); String name = rs.getString("name"); // ← カーソルが適切に位置していない可能性がある // OK:next() の戻り値を確認してから値を取得 ResultSet rs = stmt.executeQuery("SELECT * FROM users"); if (rs.next()) { String name = rs.getString("name"); // ← 安全に値を取得 } else { // データが存在しない場合の処理 }
ConstantsInInterface
公式ドキュメント: ConstantsInInterface
Since: PMD 5.5
Priority: Medium (3)
Description:
定数を定義するためにインターフェースを使用することはJavaの設計原則に反し、「Constants Interface」アンチパターンとして知られています。
これは、継承による不必要な依存関係を生み出し、実装クラスの設計を不明瞭にします。
定数はユーティリティクラスや列挙型(enum)に定義することが推奨されます。
Property:
名前 | デフォルト値 | 説明 |
---|---|---|
ignoreIfHasMethods | true | インターフェースに1つでもメソッドが定義されていれば、違反とみなさないようにします。 |
Configuration:
<!-- プロパティ設定なし --> <rule ref="category/java/bestpractices.xml/ConstantsInInterface" /> <!-- プロパティ設定あり --> <rule ref="category/java/bestpractices.xml/ConstantsInInterface"> <properties> <property name="ignoreIfHasMethods" value="false" /> </properties> </rule>
Example:
// NG: 定数だけを定義する目的でインターフェースを使用しており、継承の意図が曖昧になる public interface Constants { int TIMEOUT = 1000; } // OK: 定数をfinalクラスで定義し、インスタンス化も防止している public final class Constants { public static final int TIMEOUT = 1000; private Constants() {} // インスタンス化を防ぐためのprivateコンストラクタ }
DefaultLabelNotLastInSwitch
公式ドキュメント: DefaultLabelNotLastInSwitch
Since: PMD 1.5
Priority: Medium (3)
Description:
switch
文において、default
ラベルは最後に配置することで、コードの可読性と予測可能性が向上します。
default
が先にあると可読性が下がり、意図しないfall-throughの原因になることがあります。このルールは、default
が最後にない場合に警告を出します。
Configuration:
<rule ref="category/java/bestpractices.xml/DefaultLabelNotLastInSwitch" />
Example:
// NG:default が途中にある switch (value) { case 1: // 処理 break; default: // 処理 break; case 2: // 処理 break; } // OK:default を最後に配置 switch (value) { case 1: // 処理 break; case 2: // 処理 break; default: // 処理 break; }
DefaultLabelNotLastInSwitchStmt
公式ドキュメント: DefaultLabelNotLastInSwitchStmt
Since: PMD 1.5
Priority: Medium (3)
Description:
switch
文において、default
ラベルは通常最後に書くのが慣例であり、可読性向上や誤解の防止につながります。このルールは、default
が最後でない場合に警告を出します。
⚠️ Deprecated(非推奨):
このルールはPMD 7.7.0で名前が変更されました。ルールの機能自体は維持されており、名称が "DefaultLabelNotLastInSwitchStmt"
から "DefaultLabelNotLastInSwitch"
に変わっています。
そのため、この名前は古いものとして扱われ、新しい名前での利用が推奨されます。
Configuration:
<rule ref="category/java/bestpractices.xml/DefaultLabelNotLastInSwitchStmt" />
Example:
// NG: defaultがcaseより前にあり、fall-throughの意図が不明瞭 switch (value) { default: System.out.println("default"); break; case 1: System.out.println("one"); break; } // OK: defaultが最後に配置されている switch (value) { case 1: System.out.println("one"); break; default: System.out.println("default"); break; }
DoubleBraceInitialization
公式ドキュメント: DoubleBraceInitialization
Since: PMD 6.16.0
Priority: Medium (3)
Description:
ダブルブレースイニシャライゼーション(二重括弧での初期化)は一見便利に見えますが、匿名クラスの生成を伴い、不必要なメモリ使用や外部クラスへの不適切な参照保持につながる恐れがあります。このパターンは避けるべきです。
Configuration:
<rule ref="category/java/bestpractices.xml/DoubleBraceInitialization" />
Example:
// NG: ダブルブレースイニシャライゼーション(二重括弧での初期化)により匿名クラスが生成され、意図しない参照やメモリリークの原因になる Set<String> s = new HashSet<String>() {{ add("one"); add("two"); }}; // OK: 通常の初期化構文を使用し、安全で明確 Set<String> s = new HashSet<>(); s.add("one"); s.add("two");
ExhaustiveSwitchHasDefault
公式ドキュメント: ExhaustiveSwitchHasDefault
Since: PMD 7.10.0
Priority: Medium (3)
Description:
列挙型enumのすべての値を網羅しているswitch文にdefaultラベルが含まれている場合、それは将来的なenumの変更を見逃す原因になります。
defaultがあると、追加されたenum定数に対する警告が出なくなり、保守性が下がります。
Configuration:
<rule ref="category/java/bestpractices.xml/ExhaustiveSwitchHasDefault" />
Example:
enum Color { RED, GREEN, BLUE } // NG: enumのすべての値をcaseで処理しているにもかかわらず、defaultを含めてしまっている switch (color) { case RED: break; case GREEN: break; case BLUE: break; default: // これにより、新たなenum値追加時に警告が出なくなる break; } // OK: defaultがないため、enumの変更時に未処理のcaseを検出しやすい switch (color) { case RED: break; case GREEN: break; case BLUE: break; }
ForLoopCanBeForeach
公式ドキュメント: ForLoopCanBeForeach
Since: PMD 6.0.0
Priority: Medium (3)
Minimum Language Version: Java 1.5
Description:
for
ループでインデックスを使ってコレクションをループしている場合、foreach
(拡張for文)を使うことでコードが簡潔で可読性が高くなります。
このルールは、for
ループをforeach
に置き換えられる箇所を警告します。
Configuration:
<rule ref="category/java/bestpractices.xml/ForLoopCanBeForeach" />
Example:
// NG: インデックスを使った通常のforループで記述しているが、foreachにできる for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } // OK: 拡張for文を使うことでコードが簡潔になり、可読性が向上 for (String item : list) { System.out.println(item); }
ForLoopVariableCount
公式ドキュメント: ForLoopVariableCount
Since: PMD 6.11.0
Priority: Medium (3)
Description:
forループで複数の変数を同時に操作すると、コードの複雑性が上がり、バグを生みやすくなります。
このルールは、1つのforループで操作される変数の数が多すぎる場合に警告を出します。
Property:
名前 | デフォルト値 | 説明 |
---|---|---|
maximumVariables | 1 | 通常のfor ステートメントで許可される制御変数の最大数 |
Configuration:
<!-- プロパティ設定なし --> <rule ref="category/java/bestpractices.xml/ForLoopVariableCount" /> <!-- プロパティ設定あり --> <rule ref="category/java/bestpractices.xml/ForLoopVariableCount"> <properties> <property name="maximumVariables" value="2" /> </properties> </rule>
Example:
// NG: 3つのループ変数を同時に操作しており、可読性や保守性が低い for (int i = 0, j = 0, k = 0; i < n; i++, j++, k++) { // 複雑なループ処理 } // OK: 単一の制御変数のみを使用し、ループがシンプルで読みやすい for (int i = 0; i < n; i++) { // シンプルなループ処理 }
GuardLogStatement
公式ドキュメント: GuardLogStatement
Since: PMD 5.1.0
Priority: Medium High (2)
Description:
ログ出力の前にログレベルをチェックしないと、ログ出力処理のための文字列連結などの計算が常に実行され、パフォーマンスに悪影響を与える可能性があります。
このルールは、ログレベルのガードチェックがないログ呼び出しを検出します。
Property:
名前 | デフォルト値 | 説明 |
---|---|---|
logLevels | trace, debug, info, warn, error, log, finest, finer, fine, info, warning, severe | ガード対象となるログレベルの一覧 |
guardsMethods | isTraceEnabled, isDebugEnabled, isInfoEnabled, isWarnEnabled, isErrorEnabled, isLoggable | ログレベルチェックに使用されるメソッド |
Configuration:
<!-- プロパティ設定なし --> <rule ref="category/java/bestpractices.xml/GuardLogStatement" /> <!-- プロパティ設定あり --> <rule ref="category/java/bestpractices.xml/GuardLogStatement"> <properties> <property name="logLevels" value="debug,info" /> <property name="guardsMethods" value="isDebugEnabled,isInfoEnabled" /> </properties> </rule>
Example:
// NG: ログレベルをチェックせずに文字列連結が行われ、パフォーマンスに悪影響を与える logger.debug("User " + user.getName() + " logged in"); // OK: ログレベルをチェックし、無駄な処理を防止している if (logger.isDebugEnabled()) { logger.debug("User " + user.getName() + " logged in"); }
ImplicitFunctionalInterface
公式ドキュメント: ImplicitFunctionalInterface
Since: PMD 7.12.0
Priority: Medium High (2)
Description:
関数型インタフェース(抽象メソッドが1つだけ定義されているインタフェース)は、明示的に@FunctionalInterface
アノテーションを付けるべきです。
これにより、開発者が意図を明確に示すことができ、誤って抽象メソッドを追加することによる問題も防げます。
Configuration:
<rule ref="category/java/bestpractices.xml/ImplicitFunctionalInterface" />
Example:
// NG: 抽象メソッドが1つあるが、@FunctionalInterface が明示されていない public interface Converter<T, R> { R convert(T t); // 関数型として利用できるが、明示されていない } // OK: @FunctionalInterface があり、意図が明示されている @FunctionalInterface public interface Converter<T, R> { R convert(T t); // 意図が明確で、保守性も高い }
JUnit4SuitesShouldUseSuiteAnnotation
公式ドキュメント: JUnit4SuitesShouldUseSuiteAnnotation
Since: PMD 4.0
Priority: Medium (3)
Description:
JUnit 4では、テストスイートを作成する際には@RunWith(Suite.class)
と@Suite.SuiteClasses({...})
アノテーションを使用すべきです。
手動でのスイートクラス実装は冗長であり、保守が難しくなります。
※「JUnit4~」のルールはJUnit3→JUnit4でアノテーションベースになったことに対するチェック
Configuration:
<rule ref="category/java/bestpractices.xml/JUnit4SuitesShouldUseSuiteAnnotation" />
Example:
// NG: JUnitスイートを手動で定義しており、冗長でエラーの元になる public class AllTests { public static junit.framework.Test suite() { TestSuite suite = new TestSuite(); suite.addTestSuite(MyTest.class); return suite; } } // OK: アノテーションを使用してスイートを定義 @RunWith(Suite.class) @Suite.SuiteClasses({ MyTest.class }) public class AllTests { // クラス本体は不要 }
JUnit4TestShouldUseAfterAnnotation
公式ドキュメント: JUnit4TestShouldUseAfterAnnotation
Since: PMD PMD 4.0
Priority: Medium (3)
Description:
JUnit 4では、テスト後のクリーンアップ処理はtearDown()メソッドをオーバーライドするのではなく、@Afterアノテーションを使用するべきです。
これはJUnit 4の推奨スタイルであり、明示的であると同時に可読性も高まります。
⚠️ Deprecated(非推奨):
このルールは PMD 7.0.0 で UnitTestShouldUseAfterAnnotation
に名称変更されました。今後は新しい名前のルールを使用してください。
Configuration:
<rule ref="category/java/bestpractices.xml/JUnit4TestShouldUseAfterAnnotation" />
Example:
// NG: JUnit3スタイルの tearDown() を使用している public class MyTest extends TestCase { protected void tearDown() { // クリーンアップ処理 } } // OK: JUnit4の @After アノテーションを使用 public class MyTest { @After public void cleanUp() { // クリーンアップ処理 } }