diff --git a/data/demo-pmd/reports/AccessorAndIpDemo-review.md b/data/demo-pmd/reports/AccessorAndIpDemo-review.md new file mode 100644 index 0000000..39daa72 --- /dev/null +++ b/data/demo-pmd/reports/AccessorAndIpDemo-review.md @@ -0,0 +1,70 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\bestpractices\extra\AccessorAndIpDemo.java` +**语言:** java +**耗时:** 131.2s +**分析工具:** pmd + +--- + +总计: 17 | 错误: 3 | 警告: 13 | 建议: 1 + +静态分析 · 14 个问题 + +- 🔴 `pmd:ClassWithOnlyPrivateConstructorsShouldBeFinal` L10 + 该类只有私有构造函数,应声明为 final。 + 建议: 将类声明为 `final`,防止继承。如果类需要被实例化,应将私有构造函数改为包私有或 public。 +- 🔴 `pmd:SystemPrintln` L42 + 使用了 `System.out/err` 输出。 + 建议: 在生产代码中应使用日志框架(如 SLF4J)替代 `System.out.println`。例如定义 `private static final Logger LOG = LoggerFactory.getLogger(MiscMain.class);`,并调用 `LOG.info("demo misc");`。 +- 🟡 `pmd:MissingStaticMethodInNonInstantiatableClass` L10 + 类无法被实例化,且未提供任何静态方法或静态字段。 + 建议: 如果该类是工具类,应声明为 final 并提供静态方法或静态字段;如果类需要实例化,则应将构造函数改为非私有。例如:声明为 `final class PrivateCtor` 并添加 `public static PrivateCtor getInstance() { return new PrivateCtor(); }`。 +- 🟡 `pmd:AtLeastOneConstructor` L15 + 每个类应至少声明一个构造函数。 + 建议: 为 `UsesPrivateCtor` 添加一个显式构造函数,例如 `UsesPrivateCtor() {}`。 +- 🟡 `pmd:CommentDefaultAccessModifier` L16 + 方法 `make()` 缺少默认访问修饰符的注释。 + 建议: 为方法添加 `/* package-private */` 或 `/* default */` 注释,明确默认的包私有访问权限。 +- 🟡 `pmd:AtLeastOneConstructor` L22 + 每个类应至少声明一个构造函数。 + 建议: 为 `PrivateFieldOwner` 添加一个显式构造函数,例如 `PrivateFieldOwner() {}`。 +- 🟡 `pmd:ImmutableField` L23 + 字段 `secret` 可以声明为 final。 + 建议: 如果字段在初始化后不再改变,请声明为 `private final int secret = 42;`。 +- 🟡 `pmd:CommentDefaultAccessModifier` L24 + 方法 `getSecret()` 缺少默认访问修饰符的注释。 + 建议: 为方法添加 `/* package-private */` 或 `/* default */` 注释,明确默认的包私有访问权限。 +- 🟡 `pmd:AtLeastOneConstructor` L29 + 每个类应至少声明一个构造函数。 + 建议: 为 `ReadsPrivateField` 添加一个显式构造函数,例如 `ReadsPrivateField() {}`。 +- 🟡 `pmd:CommentDefaultAccessModifier` L30 + 方法 `read(PrivateFieldOwner)` 缺少默认访问修饰符的注释。 + 建议: 为方法添加 `/* package-private */` 或 `/* default */` 注释,明确默认的包私有访问权限。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L30 + 参数 `o` 未被赋值,可以声明为 final。 + 建议: 将参数声明为 `final PrivateFieldOwner o`,表明方法内不会重新赋值。 +- 🟡 `pmd:AtLeastOneConstructor` L36 + 每个类应至少声明一个构造函数。 + 建议: 为 `HardCodedIpDemo` 添加一个显式构造函数,例如 `HardCodedIpDemo() {}`。 +- 🟡 `pmd:CommentDefaultAccessModifier` L37 + 字段 `address` 缺少默认访问修饰符的注释。 + 建议: 在字段声明前添加 `/* package-private */` 注释,明确访问权限。 +- 🟡 `pmd:AvoidUsingHardCodedIP` L37 + 不要硬编码 IP 地址 `192.168.0.1`。 + 建议: 将 IP 地址放入配置项或属性文件,在代码中通过配置读取。例如:`String address = System.getProperty("app.address", "localhost");`,如果需要使用 Spring 可用 `@Value("${app.address}")`。避免在代码中直接出现 IP 字面量。 + +AI 审查 · 3 条建议 + +- 🔴 [AI] [bug] `private-constructor-access` L17 + **外部类访问私有构造函数导致编译失败** + UsesPrivateCtor.make() 中 `return new PrivateCtor();` 试图在 PrivateCtor 类外部调用其私有构造函数。根据 Java 访问控制,private 构造函数只能被声明它的类内部访问,因此该代码无法通过编译。需要将构造函数访问级别提升,或改为通过私有类提供的静态工厂方法创建实例。 + 建议: 将 PrivateCtor 的构造函数由 private 改为包私有(或 public),例如改为 `PrivateCtor()`;或者保留私有构造,同时在 PrivateCtor 内添加 `public static PrivateCtor getInstance()`,并将调用处改为 `PrivateCtor.getInstance()`。 +- 🟡 [AI] [bug] `null-check-missing` L31 + **read() 未对参数进行空值检查** + ReadsPrivateField.read(PrivateFieldOwner o) 直接调用 o.getSecret()。若调用方传入 null,将抛出 NullPointerException。建议增加显式空值检查或使用 java.util.Objects.requireNonNull。 + 建议: 在方法开头添加 `if (o == null) { throw new NullPointerException("o"); }`;或简化为 `java.util.Objects.requireNonNull(o, "o");`。 +- 🔵 [AI] [design] `unused-field` L37 + **字段 address 声明后从未被使用** + HardCodedIpDemo.address 字段在类中没有任何方法读取或使用它。即便移除硬编码字面量,该字段本身也可能属于无用代码。如果该字段仅用于演示规则,建议删除;如果用于配置,请提供相应的 getter 或实际使用该字段,避免维护困惑。 + 建议: 删除该字段(类体将保持为空),或为字段添加 getter 并在业务中使用。若采用配置注入,也应确保字段被消费。 diff --git a/data/demo-pmd/reports/AccessorDemo-review.md b/data/demo-pmd/reports/AccessorDemo-review.md new file mode 100644 index 0000000..5fb5a6c --- /dev/null +++ b/data/demo-pmd/reports/AccessorDemo-review.md @@ -0,0 +1,68 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\errorprone\extra\AccessorDemo.java` +**语言:** java +**耗时:** 127.9s +**分析工具:** pmd + +--- + +总计: 16 | 错误: 1 | 警告: 10 | 建议: 5 + +静态分析 · 12 个问题 + +- 🔴 `pmd:ClassWithOnlyPrivateConstructorsShouldBeFinal` L13 + 该类只有私有构造函数,应声明为 final。 + 建议: 将类声明改为 final class AccessorClass,保留私有构造函数,明确禁止继承。 +- 🟡 `pmd:CommentDefaultAccessModifier` L17 + 方法 'create()' 缺少默认访问修饰符的注释。 + 建议: 在方法前添加 /* default */ 注释,明确表达包级私有访问意图。 +- 🟡 `pmd:AtLeastOneConstructor` L22 + 每个类应至少声明一个构造函数。 + 建议: 为 AccessorUser 添加显式无参构造函数,例如 AccessorUser() {}。 +- 🟡 `pmd:CommentDefaultAccessModifier` L23 + 方法 'bad()' 缺少默认访问修饰符的注释。 + 建议: 在方法前添加 /* default */ 注释,明确表达包级私有访问意图。 +- 🟡 `pmd:UnusedLocalVariable` L25 + 避免未使用的局部变量 'a'。 + 建议: 删除该局部变量声明;如果 create() 的返回值确实是需要的,请先使用它。 +- 🟡 `pmd:LocalVariableCouldBeFinal` L26 + 局部变量 'cg' 可以声明为 final。 + 建议: 将变量声明改为 final CallerGen cg = new CallerGen();。 +- 🟡 `pmd:UnusedLocalVariable` L27 + 避免未使用的局部变量 's'。 + 建议: 删除该局部变量声明,或使用 getHidden() 的返回值。 +- 🟡 `pmd:AtLeastOneConstructor` L32 + 每个类应至少声明一个构造函数。 + 建议: 为 CallerGen 添加显式无参构造函数,例如 CallerGen() {}。 +- 🟡 `pmd:ImmutableField` L33 + 字段 'hidden' 可以被声明为 final。 + 建议: 将字段改为 private final String hidden = "x";,使字段初始化后不可变。 +- 🟡 `pmd:CommentDefaultAccessModifier` L35 + 方法 'getHidden()' 缺少默认访问修饰符的注释。 + 建议: 在方法前添加 /* default */ 注释,明确表达包级私有访问意图。 +- 🔵 `pmd:UnnecessaryImport` L9 + 未使用的导入 'java.util.ArrayList' + 建议: 删除该 import 语句,避免无效依赖。 +- 🔵 `pmd:UnnecessaryImport` L10 + 未使用的导入 'java.util.List' + 建议: 删除该 import 语句,避免无效依赖。 + +AI 审查 · 4 条建议 + +- 🟡 [AI] [bug] `dead-method` L23 + **bad() 方法无任何可观察行为,疑似调试残留** + bad() 创建了 AccessorClass 和 CallerGen 实例,并调用 getHidden(),但所有局部变量与返回值都被丢弃;方法不会写入状态、打印内容或返回结果,因此调用它没有任何可验证的效果。 + 建议: 删除该方法;如果它用于演示 getter,应返回 getHidden() 结果或使用断言校验,避免空操作。 +- 🔵 [AI] [design] `misleading-comment` L12 + **注释与代码行为不一致,示例未触发合成访问器** + 第 12 行注释声称代码涉及 AccessorClassGeneration,但 AccessorUser 只是调用 AccessorClass.create(),私有构造函数是在 AccessorClass 自身静态方法内调用,不会生成合成访问器。第 31 行也存在类似问题。这样的示例会误导读者,无法验证对应规则。 + 建议: 删除或改写相关注释,说明当前代码仅用于触发其他 PMD 规则;如需演示合成访问器,可让内部类访问外部类的私有字段,由编译器生成 synthetic accessor 方法。 +- 🔵 [AI] [performance] `stateless-factory-allocation` L17 + **AccessorClass 是无状态类,create() 每次调用都分配新实例** + AccessorClass 没有实例字段,每次调用 create() 都会 new 一个无状态对象。若该工厂方法被高频调用,会产生不必要的对象分配与 GC 压力。可改为单例持有唯一实例。 + 建议: 为 AccessorClass 添加 private static final 实例字段,并在 create() 中返回该实例;若类仅作为命名空间,也可直接使用静态方法。 +- 🔵 [AI] [design] `misleading-comment-method-generation` L31 + **AccessorMethodGeneration 注释与代码行为不符** + 第 31 行注释声称“避免合成访问器方法”,但 getHidden() 是 CallerGen 自身的普通方法,直接读取自己的私有字段;外部类只是调用该 getter,并不会触发编译器生成 synthetic accessor method。 + 建议: 将该注释改为说明性文字;如需演示 AccessorMethodGeneration,应在内部类中访问外部类私有字段。 diff --git a/data/demo-pmd/reports/AccessorGen2-review.md b/data/demo-pmd/reports/AccessorGen2-review.md new file mode 100644 index 0000000..4fa477b --- /dev/null +++ b/data/demo-pmd/reports/AccessorGen2-review.md @@ -0,0 +1,61 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\bestpractices\extra\AccessorGen2.java` +**语言:** java +**耗时:** 163.0s +**分析工具:** pmd + +--- + +总计: 14 | 错误: 3 | 警告: 11 | 建议: 0 + +静态分析 · 11 个问题 + +- 🔴 `pmd:ClassWithOnlyPrivateConstructorsShouldBeFinal` L14 + 该类只有私有构造函数,可能应设为 final。 + 建议: 将内部类 Inner 声明为 final,例如 public final class Inner。 +- 🔴 `pmd:SystemPrintln` L38 + 使用了 System.out/err 输出。 + 建议: 改用日志框架,例如 System.getLogger("AccMain").info(...),避免直接使用 System.out。 +- 🟡 `pmd:AtLeastOneConstructor` L10 + 类应至少声明一个构造函数。 + 建议: 为 AccessorClassGen 添加显式构造函数,例如 public AccessorClassGen() {}。 +- 🟡 `pmd:CommentDefaultAccessModifier` L11 + 方法 'method()' 缺少默认访问修饰符的注释。 + 建议: 在方法声明前添加 /* default */ 注释,或显式指定 public/private/protected 访问修饰符。 +- 🟡 `pmd:UnusedLocalVariable` L12 + 避免使用未使用的局部变量,例如 'ic'。 + 建议: 直接执行 new Inner() 而不是赋值给未使用的变量,或者直接删除该行。 +- 🟡 `pmd:AtLeastOneConstructor` L21 + 类应至少声明一个构造函数。 + 建议: 为 AccessorMethodGen 添加显式构造函数,例如 public AccessorMethodGen() {}。 +- 🟡 `pmd:UnusedPrivateField` L22 + 避免使用未使用的私有字段,例如 'counter'。 + 建议: 为 counter 添加 getter 方法,使其被读取,或删除该字段。 +- 🟡 `pmd:CommentDefaultAccessModifier` L25 + 构造函数 'InnerClass()' 缺少默认访问修饰符的注释。 + 建议: 在构造函数声明前添加 /* default */ 注释,或显式指定访问修饰符。 +- 🟡 `pmd:AtLeastOneConstructor` L32 + 类应至少声明一个构造函数。 + 建议: 为 HardCodedIp 添加显式构造函数,例如 HardCodedIp() {}。 +- 🟡 `pmd:CommentDefaultAccessModifier` L33 + 字段 'addr' 缺少默认访问修饰符的注释。 + 建议: 在字段声明前添加 /* default */ 注释,或显式指定 private/public/protected。 +- 🟡 `pmd:AvoidUsingHardCodedIP` L33 + 不要硬编码 IP 地址 '192.168.1.1'。 + 建议: 将 IP 地址移入配置文件或环境变量,运行时读取,例如 System.getenv("SERVER_IP"),并校验格式。 + +AI 审查 · 3 条建议 + +- 🔴 [AI] [bug] `multiple-public-top-level-classes` L21 + **同一源文件中包含多个 public 顶层类** + Java 规定一个 .java 文件只能包含一个 public 顶层类,且类名必须与文件名一致。当前第 10 行 AccessorClassGen 和第 21 行 AccessorMethodGen 均为 public,将导致编译失败。 + 建议: 将 AccessorMethodGen 改为包私有(去掉 public),或将其拆分为独立的 .java 文件。 +- 🟡 [AI] [design] `public-inner-class-with-private-constructor` L14 + **内部类 Inner 声明为 public 但构造函数为 private,API 设计矛盾** + Inner 被声明为 public,但其构造函数是 private,外部代码(除外部类 AccessorClassGen 外)无法实例化它。这种公开但不可实例化的类型会困惑调用方,应缩小可见性。 + 建议: 将 Inner 改为 private 嵌套类;若同时满足 PMD 建议,可改为 private final class Inner。 +- 🟡 [AI] [bug] `write-only-field` L22 + **counter 字段只写不读,自增操作无任何效用** + AccessorMethodGen.InnerClass 构造函数中执行 counter++,但 counter 从未被任何方法读取,该状态变化不可观测。PMD 的 UnusedPrivateField 提示了字段未使用,但更深层的问题是递增操作本身没有对应读取方,可能表明逻辑未完成或存在缺陷。 + 建议: 为 counter 添加 getter 方法以便读取计数,或移除该字段及递增语句。 diff --git a/data/demo-pmd/reports/AfterBeforeTest-review.md b/data/demo-pmd/reports/AfterBeforeTest-review.md new file mode 100644 index 0000000..20c39be --- /dev/null +++ b/data/demo-pmd/reports/AfterBeforeTest-review.md @@ -0,0 +1,53 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\errorprone\extra\AfterBeforeTest.java` +**语言:** java +**耗时:** 121.3s +**分析工具:** pmd + +--- + +总计: 11 | 错误: 2 | 警告: 9 | 建议: 0 + +静态分析 · 7 个问题 + +- 🔴 `pmd:SystemPrintln` L27 + 使用了 System.out 或 System.err 进行控制台输出。 + 建议: 建议用日志框架替代 System.out,例如 java.util.logging.Logger 的 info 方法。若为一次性调试代码,可在最终版本删除。 +- 🟡 `pmd:AtLeastOneConstructor` L8 + 每个类都应声明至少一个构造函数。 + 建议: 请为类 MissingAfterTest 添加一个显式构造函数,例如 public MissingAfterTest() {}。若不允许实例化,可设为 private。 +- 🟡 `pmd:TestClassWithoutTestCases` L8 + 类 'MissingAfterTest' 可能是一个测试类,但它不包含任何测试用例。 + 建议: 如果该类是测试类,请添加一个带有 @Test 注解的测试方法;若不需要测试,请删除该类或重命名为非测试类名称。添加注解时需引入 JUnit 依赖。 +- 🟡 `pmd:AtLeastOneConstructor` L14 + 每个类都应声明至少一个构造函数。 + 建议: 请为类 MissingBeforeTest 添加一个显式构造函数,例如 public MissingBeforeTest() {}。若不允许实例化,可设为 private。 +- 🟡 `pmd:TestClassWithoutTestCases` L14 + 类 'MissingBeforeTest' 可能是一个测试类,但它不包含任何测试用例。 + 建议: 如果该类是测试类,请添加一个带有 @Test 注解的测试方法;若不需要测试,请删除该类或重命名为非测试类名称。添加注解时需引入 JUnit 依赖。 +- 🟡 `pmd:AtLeastOneConstructor` L20 + 每个类都应声明至少一个构造函数。 + 建议: 请为类 MissingTestAnn 添加一个显式构造函数,例如 public MissingTestAnn() {}。若不允许实例化,可设为 private。 +- 🟡 `pmd:UnitTestShouldUseTestAnnotation` L21 + 单元测试应使用 @Test 注解,否则不会运行。若是 JUnit Jupiter,测试方法可使用 @RepeatedTest、@TestFactory、@TestTemplate 或 @ParameterizedTest 注解替代。 + 建议: 为 testSomething 方法添加 @Test 注解(JUnit 4/5),或根据场景改用 @RepeatedTest/@TestFactory/@TestTemplate/@ParameterizedTest。 + +AI 审查 · 4 条建议 + +- 🔴 [AI] [bug] `multiple-public-classes-in-file` L14 + **一个源文件中存在多个 public 类,无法编译** + Java 允许一个源文件中最多有一个 public 顶层类,且必须与文件名一致。当前文件中第 8、14、20 行分别声明了 MissingAfterTest、MissingBeforeTest、MissingTestAnn 三个 public 类,导致编译失败。 + 建议: 将 MissingBeforeTest 和 MissingTestAnn 改为包级私有(去掉 public),或拆分到独立文件。若文件名不是 MissingAfterTest.java,还需要调整类名或文件名使二者一致。 +- 🟡 [AI] [bug] `missing-junit-imports` L5 + **使用 JUnit 注解前未导入相关包** + 代码中已有 tearDown/setUp/testSomething 等测试相关方法,后续修复需要添加 @After/@Before/@Test 注解,但当前没有任何 JUnit 的 import 语句,添加注解后将因找不到符号而编译失败。 + 建议: 在文件顶部添加 JUnit 4 导入,例如 import org.junit.After; import org.junit.Before; import org.junit.Test;。如果使用 JUnit 5,请改为导入 org.junit.jupiter.api.*。同时确保 classpath 包含 JUnit 依赖。 +- 🟡 [AI] [design] `empty-lifecycle-method` L9 + **空的 setUp/tearDown 生命周期方法没有实际作用** + MissingAfterTest.tearDown 与 MissingBeforeTest.setUp 方法体为空,即使补充 @After/@Before 注解,也不会执行任何初始化或清理逻辑,容易引入误导。 + 建议: 在方法中实现实际的资源初始化/清理逻辑;如果不需要,则删除这两个空方法。 +- 🟡 [AI] [design] `missing-assertions-in-test` L21 + **testSomething 方法缺少断言,测试无效** + MissingTestAnn.testSomething 方法即使添加 @Test 注解,也因为没有断言而无法验证任何行为,空测试会通过并掩盖回归问题。 + 建议: 在该方法中补充实际的断言,例如使用 org.junit.jupiter.api.Assertions 中的 assertEquals、assertNotNull 等方法,验证被测对象的行为和预期结果。 diff --git a/data/demo-pmd/reports/ApiService-review.md b/data/demo-pmd/reports/ApiService-review.md new file mode 100644 index 0000000..c3fe94a --- /dev/null +++ b/data/demo-pmd/reports/ApiService-review.md @@ -0,0 +1,30 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\api\ApiService.java` +**语言:** java +**耗时:** 74.4s +**分析工具:** pmd + +--- + +总计: 4 | 错误: 1 | 警告: 2 | 建议: 1 + +静态分析 · 2 个问题 + +- 🔴 `pmd:SystemPrintln` L11 + 使用了 System.out/err 进行输出 + 建议: 改用日志框架输出,例如:private static final java.util.logging.Logger LOGGER = java.util.logging.Logger.getLogger(ApiService.class.getName()); 然后调用 LOGGER.info("api service");。这样支持日志级别、格式化与可配置化输出。 +- 🟡 `pmd:AtLeastOneConstructor` L9 + 每个类应至少声明一个构造函数 + 建议: 为 ApiService 类添加一个显式构造函数,例如:public ApiService() { }。这样可以显式控制实例化过程,并为后续可能的依赖注入留出扩展点。 + +AI 审查 · 2 条建议 + +- 🟡 [AI] [design] `static-method` L10 + **doWork 方法不访问实例状态,应声明为 static** + doWork() 方法只执行输出操作,未使用任何实例字段或实例方法,因此没有理由要求调用方创建 ApiService 实例。声明为 static 后,可通过 ApiService.doWork() 直接调用,避免不必要的对象分配,也更清晰地表达其工具方法语义。 + 建议: 将方法签名改为 public static void doWork(),并更新调用方为 ApiService.doWork()。 +- 🔵 [AI] [style] `magic-string` L11 + **魔法字符串 "api service" 应提取为常量** + 字符串字面量 "api service" 直接出现在代码中,若消息内容在别处也需要使用,重复字面量容易导致不一致。建议提取为静态常量或使用资源文件,提升可维护性与可测试性。 + 建议: 在类中定义 private static final String MESSAGE = "api service";,并将输出语句改为 System.out.println(MESSAGE);。 diff --git a/data/demo-pmd/reports/AssertStmtTest-review.md b/data/demo-pmd/reports/AssertStmtTest-review.md new file mode 100644 index 0000000..3dd1ed0 --- /dev/null +++ b/data/demo-pmd/reports/AssertStmtTest-review.md @@ -0,0 +1,54 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\errorprone\extra\AssertStmtTest.java` +**语言:** java +**耗时:** 112.2s +**分析工具:** pmd + +--- + +总计: 12 | 错误: 4 | 警告: 7 | 建议: 1 + +静态分析 · 10 个问题 + +- 🔴 `pmd:WrongTestAnnotation` L10 + org.junit.Test 注解来自 JUnit 4,而当前代码库使用的是 JUnit Jupiter。 + 建议: 将 import org.junit.Test; 改为 import org.junit.jupiter.api.Test;,并确保使用 JUnit Jupiter 依赖。 +- 🔴 `pmd:WrongTestAnnotation` L19 + org.junit.Test 注解来自 JUnit 4,而当前代码库使用的是 JUnit Jupiter。 + 建议: 改用在 JUnit Jupiter 下用 assertThrows 断言异常:将 @Test(expected = ArithmeticException.class) 改为 @Test,并在方法内使用 Assertions.assertThrows 包裹除零逻辑。 +- 🔴 `pmd:SystemPrintln` L27 + 使用了 System.out/err 输出。 + 建议: 建议使用日志框架(如 java.util.logging、SLF4J)替代 System.out 输出。 +- 🟡 `pmd:AtLeastOneConstructor` L9 + 每个类应至少声明一个构造函数 + 建议: 为 AssertStmtTest 类显式添加一个构造函数,例如:public AssertStmtTest() {} +- 🟡 `pmd:UnitTestShouldIncludeAssert` L11 + 该单元测试应包含 assert() 或 fail()。 + 建议: 在测试方法中增加断言,例如使用 org.junit.jupiter.api.Assertions.assertEquals(1, x) 替代 assert x == 1。 +- 🟡 `pmd:LocalVariableCouldBeFinal` L12 + 局部变量 'x' 可以声明为 final。 + 建议: 将 int x = 1; 改为 final int x = 1;,表示变量初始化后不再变化。 +- 🟡 `pmd:AssertStatementInTest` L13 + 测试代码中不应使用 assert 语句。 + 建议: 不要使用 Java 关键字 assert,改用 JUnit 断言方法,例如 assertEquals(1, x)。 +- 🟡 `pmd:AtLeastOneConstructor` L18 + 每个类应至少声明一个构造函数 + 建议: 为 JUnitExpectedTest 类显式添加一个构造函数,例如:JUnitExpectedTest() {}。 +- 🟡 `pmd:PublicMemberInNonPublicType` L20 + 公共成员 'testExpected' 声明在非公共类型中。 + 建议: 由于一个 .java 文件只能有一个 public 类,此处应将测试方法改为包私有可见性:将 public void testExpected() 改为 void testExpected()。 +- 🟡 `pmd:UnusedLocalVariable` L21 + 避免未使用的局部变量 'x'。 + 建议: 删除未使用的变量,或直接在断言 lambda 中使用该表达式,例如:assertThrows(ArithmeticException.class, () -> { int zero = 0; if (1 / zero == 0) {} })。 + +AI 审查 · 2 条建议 + +- 🔴 [AI] [bug] `constant-division-by-zero` L21 + **常量除零导致编译失败** + 第21行的 `int x = 1 / 0;` 中,1 和 0 都是整数常量表达式,Java 编译器会在编译期直接计算并报错 'division by zero',导致整个源文件无法编译。PMD 未检查编译期错误,因此需要手动修复。 + 建议: 将除数改为非常量表达式,例如使用变量 `int zero = 0; int x = 1 / zero;`,或者改用 `assertThrows(ArithmeticException.class, () -> { int zero = 0; if (1 / zero == 0) {} })`,确保除零发生在运行时。 +- 🔵 [AI] [design] `no-private-constructor-for-main-class` L25 + **包含 main 方法的类未提供私有构造函数** + AssertMain 是一个仅包含静态 main 方法的入口类,不应被实例化。建议添加私有构造函数,避免外部创建实例,同时满足构造相关设计约束。 + 建议: 在 AssertMain 类中添加私有构造函数:`private AssertMain() { throw new AssertionError(); }`,并将类声明为 final(可选)。 diff --git a/data/demo-pmd/reports/BestPracticesCodeStyle-review.md b/data/demo-pmd/reports/BestPracticesCodeStyle-review.md new file mode 100644 index 0000000..b8887a5 --- /dev/null +++ b/data/demo-pmd/reports/BestPracticesCodeStyle-review.md @@ -0,0 +1,1078 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\bpcs\BestPracticesCodeStyle.java` +**语言:** java +**耗时:** 290.6s +**分析工具:** pmd + +--- + +总计: 524 | 错误: 78 | 警告: 416 | 建议: 30 + +静态分析 · 517 个问题 + +- 🔴 `pmd:SystemPrintln` L51 + Usage of System.out/err +- 🔴 `pmd:ImplicitFunctionalInterface` L109 + Annotate this interface with @FunctionalInterface or with @SuppressWarnings("PMD.ImplicitFunctionalInterface") to clarify your intent. +- 🔴 `pmd:AvoidFileStream` L130 + Avoid instantiating FileInputStream, FileOutputStream, FileReader, or FileWriter +- 🔴 `pmd:SystemPrintln` L158 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L159 + Usage of System.out/err +- 🔴 `pmd:AvoidFileStream` L166 + Avoid instantiating FileInputStream, FileOutputStream, FileReader, or FileWriter +- 🔴 `pmd:AvoidFileStream` L176 + Avoid instantiating FileInputStream, FileOutputStream, FileReader, or FileWriter +- 🔴 `pmd:AvoidThrowingRawExceptionTypes` L240 + Avoid throwing raw exception type RuntimeException. +- 🔴 `pmd:AvoidReassigningParameters` L259 + Avoid reassigning parameters such as 'x' +- 🔴 `pmd:AvoidThrowingRawExceptionTypes` L359 + Avoid throwing raw exception type RuntimeException. +- 🔴 `pmd:SystemPrintln` L384 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L392 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L401 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L410 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L448 + Usage of System.out/err +- 🔴 `pmd:FieldNamingConventions` L458 + The constant name 'log' doesn't match '[A-Z][A-Z_0-9]*' +- 🔴 `pmd:GuardLogStatement` L461 + Logger calls should be surrounded by log level guards. +- 🔴 `pmd:SystemPrintln` L480 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L508 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L523 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L539 + Usage of System.out/err +- 🔴 `pmd:ClassNamingConventions` L554 + The class name 'Bad$Name' doesn't match '[A-Z][a-zA-Z0-9]*' +- 🔴 `pmd:ClassNamingConventions` L582 + The class name 'badClassName' doesn't match '[A-Z][a-zA-Z0-9]*' +- 🔴 `pmd:SystemPrintln` L607 + Usage of System.out/err +- 🔴 `pmd:EmptyMethodInAbstractClassShouldBeAbstract` L621 + An empty method in an abstract class should be abstract instead +- 🔴 `pmd:FieldNamingConventions` L638 + The field name 'bad_name' doesn't match '[a-z][a-zA-Z0-9]*' +- 🔴 `pmd:FinalParameterInAbstractMethod` L643 + Final parameter in abstract method +- 🔴 `pmd:FormalParameterNamingConventions` L658 + The method parameter name 'bad_param' doesn't match '[a-z][a-zA-Z0-9]*' +- 🔴 `pmd:SystemPrintln` L668 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L670 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L693 + Usage of System.out/err +- 🔴 `pmd:LocalVariableNamingConventions` L700 + The local variable name 'bad_var' doesn't match '[a-z][a-zA-Z0-9]*' +- 🔴 `pmd:SystemPrintln` L701 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L708 + Usage of System.out/err +- 🔴 `pmd:MethodNamingConventions` L714 + The instance method name 'BadMethod' doesn't match '[a-z][a-zA-Z0-9]*' +- 🔴 `pmd:ModifierOrder` L720 + Missorted modifiers `static public`. +- 🔴 `pmd:ModifierOrder` L722 + Missorted modifiers `final private`. +- 🔴 `pmd:SystemPrintln` L739 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L740 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L741 + Usage of System.out/err +- 🔴 `pmd:StringInstantiation` L796 + Avoid instantiating String objects; this is usually unnecessary. +- 🔴 `pmd:ImplicitFunctionalInterface` L805 + Annotate this interface with @FunctionalInterface or with @SuppressWarnings("PMD.ImplicitFunctionalInterface") to clarify your intent. +- 🔴 `pmd:SystemPrintln` L812 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L821 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L834 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L842 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L851 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L869 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L877 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L878 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L879 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L880 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L881 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L882 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L888 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L926 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L943 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L951 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L952 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L953 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L954 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L958 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L986 + Usage of System.out/err +- 🔴 `pmd:AvoidUsingNativeCode` L1006 + The use of native code is not recommended. +- 🔴 `pmd:SystemPrintln` L1025 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1026 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1027 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1028 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1029 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1030 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1031 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1032 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1033 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1034 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1038 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1044 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1053 + Usage of System.out/err +- 🟡 `pmd:TooManyStaticImports` L29 + Too many static imports may lead to messy code +- 🟡 `pmd:AtLeastOneConstructor` L48 + Each class should declare at least one constructor +- 🟡 `pmd:AbstractClassWithoutAbstractMethod` L48 + This abstract class does not have any abstract methods +- 🟡 `pmd:PublicMemberInNonPublicType` L50 + Public member 'start' declared in a non-public type +- 🟡 `pmd:CommentDefaultAccessModifier` L59 + Missing commented default access modifier on constructor 'DataProcessor(String[])' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L59 + Parameter 'input' is not assigned and could be declared final +- 🟡 `pmd:ArrayIsStoredDirectly` L60 + The user-supplied array 'input' is stored directly. +- 🟡 `pmd:PublicMemberInNonPublicType` L63 + Public member 'getItems' declared in a non-public type +- 🟡 `pmd:MethodReturnsInternalArray` L64 + Returning 'items' may expose an internal array. +- 🟡 `pmd:AvoidMessageDigestField` L71 + You shouldnt declare field of MessageDigest type, because unsynchronized access could cause problems +- 🟡 `pmd:UnusedPrivateField` L71 + Avoid unused private fields such as 'digest'. +- 🟡 `pmd:CommentDefaultAccessModifier` L73 + Missing commented default access modifier on constructor 'Hasher()' +- 🟡 `pmd:AvoidCatchingGenericException` L76 + Avoid catching Exception in try-catch block +- 🟡 `pmd:AtLeastOneConstructor` L83 + Each class should declare at least one constructor +- 🟡 `pmd:AvoidStringBufferField` L84 + StringBuffers can grow quite a lot, and so may become a source of memory leak (if the owning class has a long life time). +- 🟡 `pmd:ImmutableField` L84 + Field 'sb' may be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L86 + Missing commented default access modifier on method 'add(String)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L86 + Parameter 's' is not assigned and could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L92 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L93 + Missing commented default access modifier on field 'host' +- 🟡 `pmd:ConstantsInInterface` L98 + Using constants in interfaces is a bad practice. +- 🟡 `pmd:AtLeastOneConstructor` L102 + Each class should declare at least one constructor +- 🟡 `pmd:UseConcurrentHashMap` L103 + If you run in Java5 or newer and have concurrent access, you should use the ConcurrentHashMap implementation +- 🟡 `pmd:CommentDefaultAccessModifier` L103 + Missing commented default access modifier on field 'map' +- 🟡 `pmd:UseDiamondOperator` L103 + Explicit type arguments can be replaced by a diamond: `new HashMap<>()` +- 🟡 `pmd:DoubleBraceInitialization` L103 + Double-brace initialization should be avoided +- 🟡 `pmd:AtLeastOneConstructor` L114 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L115 + Missing commented default access modifier on method 'outer()' +- 🟡 `pmd:AvoidLiteralsInIfCondition` L119 + Avoid using literals such as 2 in if statements +- 🟡 `pmd:AtLeastOneConstructor` L128 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L129 + Missing commented default access modifier on method 'read()' +- 🟡 `pmd:CloseResource` L130 + Ensure that resources like this FileInputStream object are closed after use +- 🟡 `pmd:LocalVariableCouldBeFinal` L130 + Local variable 'fis' could be declared final +- 🟡 `pmd:CloseResource` L131 + Ensure that resources like this InputStreamReader object are closed after use +- 🟡 `pmd:LocalVariableCouldBeFinal` L131 + Local variable 'isr' could be declared final +- 🟡 `pmd:RelianceOnDefaultCharset` L131 + Specify a character set instead of relying on the default charset +- 🟡 `pmd:CloseResource` L132 + Ensure that resources like this BufferedReader object are closed after use +- 🟡 `pmd:LocalVariableCouldBeFinal` L132 + Local variable 'br' could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L138 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L139 + Missing commented default access modifier on method 'list()' +- 🟡 `pmd:LooseCoupling` L140 + Avoid using implementation types like 'Hashtable'; use the interface instead +- 🟡 `pmd:ReplaceHashtableWithMap` L140 + Consider replacing this Hashtable with the newer java.util.Map +- 🟡 `pmd:LocalVariableCouldBeFinal` L140 + Local variable 'h' could be declared final +- 🟡 `pmd:ReplaceHashtableWithMap` L140 + Consider replacing this Hashtable with the newer java.util.Map +- 🟡 `pmd:UnusedLocalVariable` L141 + Avoid unused local variables such as 'e'. +- 🟡 `pmd:AtLeastOneConstructor` L146 + Each class should declare at least one constructor +- 🟡 `pmd:LooseCoupling` L147 + Avoid using implementation types like 'Hashtable'; use the interface instead +- 🟡 `pmd:ReplaceHashtableWithMap` L147 + Consider replacing this Hashtable with the newer java.util.Map +- 🟡 `pmd:CommentDefaultAccessModifier` L147 + Missing commented default access modifier on field 'table' +- 🟡 `pmd:ReplaceHashtableWithMap` L147 + Consider replacing this Hashtable with the newer java.util.Map +- 🟡 `pmd:AtLeastOneConstructor` L151 + Each class should declare at least one constructor +- 🟡 `pmd:LooseCoupling` L152 + Avoid using implementation types like 'Vector'; use the interface instead +- 🟡 `pmd:ReplaceVectorWithList` L152 + Consider replacing this Vector with the newer java.util.List +- 🟡 `pmd:CommentDefaultAccessModifier` L152 + Missing commented default access modifier on field 'v' +- 🟡 `pmd:ReplaceVectorWithList` L152 + Consider replacing this Vector with the newer java.util.List +- 🟡 `pmd:UseArrayListInsteadOfVector` L152 + Use ArrayList instead of Vector +- 🟡 `pmd:AtLeastOneConstructor` L156 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L157 + Missing commented default access modifier on method 'log()' +- 🟡 `pmd:AtLeastOneConstructor` L164 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L165 + Missing commented default access modifier on method 'doIt()' +- 🟡 `pmd:CloseResource` L166 + Ensure that resources like this FileInputStream object are closed after use +- 🟡 `pmd:LocalVariableCouldBeFinal` L166 + Local variable 'fis' could be declared final +- 🟡 `pmd:CloseResource` L167 + Ensure that resources like this InputStreamReader object are closed after use +- 🟡 `pmd:LocalVariableCouldBeFinal` L167 + Local variable 'isr' could be declared final +- 🟡 `pmd:UseStandardCharsets` L167 + Please use StandardCharsets constants +- 🟡 `pmd:CloseResource` L168 + Ensure that resources like this BufferedReader object are closed after use +- 🟡 `pmd:LocalVariableCouldBeFinal` L168 + Local variable 'br' could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L174 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L175 + Missing commented default access modifier on method 'read()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L176 + Local variable 'br' could be declared final +- 🟡 `pmd:RelianceOnDefaultCharset` L176 + Specify a character set instead of relying on the default charset +- 🟡 `pmd:UseTryWithResources` L177 + Consider using a try-with-resources statement instead of explicitly closing the resource +- 🟡 `pmd:AtLeastOneConstructor` L186 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L187 + Missing commented default access modifier on method 'accept(String[])' +- 🟡 `pmd:AtLeastOneConstructor` L193 + Each class should declare at least one constructor +- 🟡 `pmd:RedundantFieldInitializer` L194 + Avoid using redundant field initializer for 'i' +- 🟡 `pmd:CommentDefaultAccessModifier` L194 + Missing commented default access modifier on field 'i' +- 🟡 `pmd:CommentDefaultAccessModifier` L195 + Missing commented default access modifier on method 'loop()' +- 🟡 `pmd:AssignmentInOperand` L197 + Avoid assignment to i in operand +- 🟡 `pmd:AvoidLiteralsInIfCondition` L197 + Avoid using literals such as 5 in if statements +- 🟡 `pmd:AtLeastOneConstructor` L205 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L206 + Missing commented default access modifier on field 'a' +- 🟡 `pmd:AtLeastOneConstructor` L210 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L211 + Missing commented default access modifier on method 'call()' +- 🟡 `pmd:UnnecessaryVarargsArrayCreation` L212 + Unnecessary explicit array creation for varargs method call +- 🟡 `pmd:CommentDefaultAccessModifier` L214 + Missing commented default access modifier on method 'accept2(String[])' +- 🟡 `pmd:AtLeastOneConstructor` L220 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L221 + Public member 'm' declared in a non-public type +- 🟡 `pmd:AtLeastOneConstructor` L226 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L227 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:UnusedLocalVariable` L229 + Avoid unused local variables such as 'x'. +- 🟡 `pmd:AvoidPrintStackTrace` L231 + Avoid printStackTrace(); use a logger call instead. +- 🟡 `pmd:AtLeastOneConstructor` L237 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L238 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:ExceptionAsFlowControl` L241 + Exception thrown at line 240 is caught in this block. +- 🟡 `pmd:AvoidCatchingGenericException` L241 + Avoid catching RuntimeException in try-catch block +- 🟡 `pmd:UnusedAssignment` L241 + The initial value of exception parameter 'e' is never used (overwritten on line 242) +- 🟡 `pmd:AvoidReassigningCatchVariables` L242 + Avoid reassigning caught exception 'e' +- 🟡 `pmd:UnusedAssignment` L242 + The value assigned to variable 'e' is never used +- 🟡 `pmd:AtLeastOneConstructor` L248 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L249 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:AvoidReassigningLoopVariables` L251 + Avoid reassigning the loop control variable 'i' +- 🟡 `pmd:AtLeastOneConstructor` L257 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L258 + Missing commented default access modifier on method 'bad(int)' +- 🟡 `pmd:UnusedAssignment` L258 + The initial value of parameter 'x' is never used (overwritten on line 259) +- 🟡 `pmd:UnusedAssignment` L259 + The value assigned to variable 'x' is never used +- 🟡 `pmd:AtLeastOneConstructor` L264 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L265 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:CloseResource` L267 + Ensure that resources like this Statement object are closed after use +- 🟡 `pmd:LocalVariableCouldBeFinal` L267 + Local variable 'st' could be declared final +- 🟡 `pmd:CloseResource` L268 + Ensure that resources like this ResultSet object are closed after use +- 🟡 `pmd:LocalVariableCouldBeFinal` L268 + Local variable 'rs' could be declared final +- 🟡 `pmd:CheckResultSet` L269 + Always check the return of one of the navigation method (next,previous,first,last) of a ResultSet. +- 🟡 `pmd:EmptyCatchBlock` L270 + Avoid empty catch blocks +- 🟡 `pmd:AvoidCatchingGenericException` L270 + Avoid catching Exception in try-catch block +- 🟡 `pmd:AtLeastOneConstructor` L276 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L277 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L278 + Local variable 'c' could be declared final +- 🟡 `pmd:EmptyControlStatement` L279 + Empty if statement +- 🟡 `pmd:EnumComparison` L279 + Enums should be compared using == +- 🟡 `pmd:CommentDefaultAccessModifier` L282 + Missing commented default access modifier on nested enum 'Color' +- 🟡 `pmd:AtLeastOneConstructor` L286 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L287 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L288 + Local variable 'c' could be declared final +- 🟡 `pmd:ExhaustiveSwitchHasDefault` L289 + The switch block is exhaustive even without the default case +- 🟡 `pmd:CommentDefaultAccessModifier` L295 + Missing commented default access modifier on nested enum 'Color' +- 🟡 `pmd:AtLeastOneConstructor` L299 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L300 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:EmptyControlStatement` L301 + Empty for statement +- 🟡 `pmd:ForLoopVariableCount` L301 + Too many control variables in the for statement +- 🟡 `pmd:UnusedAssignment` L301 + The updated value of variable 'j' is never used +- 🟡 `pmd:AtLeastOneConstructor` L307 + Each class should declare at least one constructor +- 🟡 `pmd:AvoidFieldNameMatchingMethodName` L308 + Field LOG has the same name as a method +- 🟡 `pmd:CommentDefaultAccessModifier` L309 + Missing commented default access modifier on method 'log(String)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L309 + Parameter 'msg' is not assigned and could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L315 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L316 + Missing commented default access modifier on method 'bad(String)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L316 + Parameter 's' is not assigned and could be declared final +- 🟡 `pmd:EmptyControlStatement` L317 + Empty if statement +- 🟡 `pmd:LiteralsFirstInComparisons` L317 + Position literals first in String comparisons +- 🟡 `pmd:AtLeastOneConstructor` L323 + Each class should declare at least one constructor +- 🟡 `pmd:MissingOverride` L324 + The method 'toString()' is missing an @Override annotation. +- 🟡 `pmd:OverrideBothEqualsAndHashcode` L327 + Ensure you override both equals() and hashCode() +- 🟡 `pmd:MissingOverride` L327 + The method 'equals(Object)' is missing an @Override annotation. +- 🟡 `pmd:AtLeastOneConstructor` L331 + Each class should declare at least one constructor +- 🟡 `pmd:MissingOverride` L332 + The method 'toString()' is missing an @Override annotation. +- 🟡 `pmd:AtLeastOneConstructor` L336 + Each class should declare at least one constructor +- 🟡 `pmd:OverrideBothEqualsAndHashcode` L337 + Ensure you override both equals() and hashCode() +- 🟡 `pmd:MissingOverride` L337 + The method 'equals(Object)' is missing an @Override annotation. +- 🟡 `pmd:AtLeastOneConstructor` L343 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L344 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L345 + Local variable 'c' could be declared final +- 🟡 `pmd:TooFewBranchesForSwitch` L346 + A switch with less than three branches is inefficient, use a if statement instead. +- 🟡 `pmd:NonExhaustiveSwitch` L346 + Switch statements or expressions should be exhaustive, add a default case (or missing enum branches) +- 🟡 `pmd:CommentDefaultAccessModifier` L350 + Missing commented default access modifier on nested enum 'Color2' +- 🟡 `pmd:AtLeastOneConstructor` L354 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L355 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:ExceptionAsFlowControl` L358 + Exception thrown at line 357 is caught in this block. +- 🟡 `pmd:PreserveStackTrace` L359 + Thrown exception does not preserve the stack trace of exception 'e' on all code paths +- 🟡 `pmd:AtLeastOneConstructor` L365 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L366 + Missing commented default access modifier on field 'i' +- 🟡 `pmd:PrimitiveWrapperInstantiation` L366 + Do not use `new Integer(...)`, prefer `Integer.valueOf(...)` +- 🟡 `pmd:UnnecessaryBoxing` L366 + Unnecessary explicit boxing +- 🟡 `pmd:AtLeastOneConstructor` L370 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L371 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L372 + Local variable 'x' could be declared final +- 🟡 `pmd:TooFewBranchesForSwitch` L373 + A switch with less than three branches is inefficient, use a if statement instead. +- 🟡 `pmd:DefaultLabelNotLastInSwitch` L374 + The default label should be the last label in a switch statement or expression +- 🟡 `pmd:AtLeastOneConstructor` L381 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L382 + Missing commented default access modifier on method 'bad(List)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L382 + Parameter 'l' is not assigned and could be declared final +- 🟡 `pmd:ForLoopCanBeForeach` L383 + This for loop can be replaced by a foreach loop +- 🟡 `pmd:AtLeastOneConstructor` L390 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L391 + Missing commented default access modifier on method 'bad(int)' +- 🟡 `pmd:AtLeastOneConstructor` L397 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L398 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:UnusedLabel` L399 + Avoid unused labels such as 'label'. +- 🟡 `pmd:AtLeastOneConstructor` L407 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L408 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:UnusedLocalVariable` L409 + Avoid unused local variables such as 'x'. +- 🟡 `pmd:AtLeastOneConstructor` L415 + Each class should declare at least one constructor +- 🟡 `pmd:UnusedPrivateField` L416 + Avoid unused private fields such as 'secret'. +- 🟡 `pmd:PublicMemberInNonPublicType` L417 + Public member 'm' declared in a non-public type +- 🟡 `pmd:AtLeastOneConstructor` L422 + Each class should declare at least one constructor +- 🟡 `pmd:UnusedPrivateMethod` L423 + Avoid unused private methods such as 'helper()'. +- 🟡 `pmd:PublicMemberInNonPublicType` L425 + Public member 'm' declared in a non-public type +- 🟡 `pmd:AtLeastOneConstructor` L430 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L431 + Missing commented default access modifier on method 'bad(List)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L431 + Parameter 'l' is not assigned and could be declared final +- 🟡 `pmd:EmptyControlStatement` L432 + Empty if statement +- 🟡 `pmd:UseCollectionIsEmpty` L432 + Substitute calls to size() == 0 (or size() != 0, size() > 0, size() < 1) with calls to isEmpty() +- 🟡 `pmd:AtLeastOneConstructor` L438 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L439 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:LooseCoupling` L440 + Avoid using implementation types like 'HashSet'; use the interface instead +- 🟡 `pmd:UnusedLocalVariable` L440 + Avoid unused local variables such as 'set'. +- 🟡 `pmd:UseEnumCollections` L440 + This collection could be an EnumSet +- 🟡 `pmd:LooseCoupling` L441 + Avoid using implementation types like 'HashMap'; use the interface instead +- 🟡 `pmd:UnusedLocalVariable` L441 + Avoid unused local variables such as 'map'. +- 🟡 `pmd:UseEnumCollections` L441 + This collection could be an EnumMap +- 🟡 `pmd:CommentDefaultAccessModifier` L443 + Missing commented default access modifier on nested enum 'Color' +- 🟡 `pmd:AtLeastOneConstructor` L457 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L460 + Missing commented default access modifier on method 'debug(String, String)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L460 + Parameter 'param1' is not assigned and could be declared final +- 🟡 `pmd:MethodArgumentCouldBeFinal` L460 + Parameter 'param2' is not assigned and could be declared final +- 🟡 `pmd:LabeledStatement` L471 + Avoid using labeled statements such as 'lbl2'. +- 🟡 `pmd:AvoidLiteralsInIfCondition` L472 + Avoid using literals such as 3 in if statements +- 🟡 `pmd:UnusedLabel` L476 + Avoid unused labels such as 'lbl3'. +- 🟡 `pmd:AvoidLiteralsInIfCondition` L477 + Avoid using literals such as 4 in if statements +- 🟡 `pmd:AtLeastOneConstructor` L487 + Each class should declare at least one constructor +- 🟡 `pmd:ReplaceEnumerationWithIterator` L487 + Consider replacing this Enumeration with the newer java.util.Iterator +- 🟡 `pmd:RedundantFieldInitializer` L488 + Avoid using redundant field initializer for 'i' +- 🟡 `pmd:MissingOverride` L490 + The method 'hasMoreElements()' is missing an @Override annotation. +- 🟡 `pmd:MissingOverride` L494 + The method 'nextElement()' is missing an @Override annotation. +- 🟡 `pmd:AssignmentInOperand` L495 + Avoid assignment to i in operand +- 🟡 `pmd:AtLeastOneConstructor` L500 + Each class should declare at least one constructor +- 🟡 `pmd:AtLeastOneConstructor` L506 + Each class should declare at least one constructor +- 🟡 `pmd:UnusedPrivateMethod` L507 + Avoid unused private methods such as 'bar(String)'. +- 🟡 `pmd:UnusedFormalParameter` L507 + Avoid unused method parameters such as 'howdy'. +- 🟡 `pmd:AtLeastOneConstructor` L513 + Each class should declare at least one constructor +- 🟡 `pmd:NonStaticInitializer` L514 + Non-static initializers are confusing +- 🟡 `pmd:EmptyControlStatement` L515 + Empty do..while statement +- 🟡 `pmd:WhileLoopWithLiteralBoolean` L517 + The loop can be simplified. +- 🟡 `pmd:UnnecessaryWarningSuppression` L531 + Unnecessary PMD suppression comment +- 🟡 `pmd:AtLeastOneConstructor` L532 + Each class should declare at least one constructor +- 🟡 `pmd:AtLeastOneConstructor` L548 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L549 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:AvoidDollarSigns` L554 + Avoid using dollar signs in variable/method/class/interface names +- 🟡 `pmd:AtLeastOneConstructor` L554 + Each class should declare at least one constructor +- 🟡 `pmd:AtLeastOneConstructor` L558 + Each class should declare at least one constructor +- 🟡 `pmd:AvoidProtectedFieldInFinalClass` L559 + Avoid protected fields in a final class. Change to private or package access. +- 🟡 `pmd:AtLeastOneConstructor` L563 + Each class should declare at least one constructor +- 🟡 `pmd:AvoidProtectedMethodInFinalClassNotExtending` L564 + Avoid protected methods in a final class that doesnt extend anything other than Object. Change to private or package access. +- 🟡 `pmd:AtLeastOneConstructor` L569 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L570 + Missing commented default access modifier on method 'jni()' +- 🟡 `pmd:AtLeastOneConstructor` L574 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L575 + Missing commented default access modifier on field 'flag' +- 🟡 `pmd:CommentDefaultAccessModifier` L576 + Missing commented default access modifier on method 'getFlag()' +- 🟡 `pmd:AtLeastOneConstructor` L582 + Each class should declare at least one constructor +- 🟡 `pmd:AtLeastOneConstructor` L586 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L587 + Missing commented default access modifier on field 'x' +- 🟡 `pmd:CommentDefaultAccessModifier` L588 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:AtLeastOneConstructor` L593 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L594 + Missing commented default access modifier on method 'bad(boolean)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L594 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:ConfusingTernary` L595 + Avoid if (x != y) ..; else ..; +- 🟡 `pmd:SimplifyBooleanReturns` L595 + This if statement can be replaced by `return {condition};` +- 🟡 `pmd:OnlyOneReturn` L596 + A method should have only one exit point, and that should be the last statement in the method +- 🟡 `pmd:AtLeastOneConstructor` L604 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L605 + Missing commented default access modifier on method 'bad(boolean)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L605 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:ControlStatementBraces` L607 + This statement should have braces +- 🟡 `pmd:AtLeastOneConstructor` L612 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L613 + Missing commented default access modifier on method 'bad(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L613 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:EmptyControlStatement` L614 + Empty if statement +- 🟡 `pmd:AtLeastOneConstructor` L620 + Each class should declare at least one constructor +- 🟡 `pmd:AbstractClassWithoutAbstractMethod` L620 + This abstract class does not have any abstract methods +- 🟡 `pmd:CommentDefaultAccessModifier` L621 + Missing commented default access modifier on method 'empty()' +- 🟡 `pmd:AtLeastOneConstructor` L626 + Each class should declare at least one constructor +- 🟡 `pmd:AtLeastOneConstructor` L630 + Each class should declare at least one constructor +- 🟡 `pmd:UnusedPrivateField` L631 + Avoid unused private fields such as 'late'. +- 🟡 `pmd:CommentDefaultAccessModifier` L632 + Missing commented default access modifier on method 'method()' +- 🟡 `pmd:AtLeastOneConstructor` L637 + Each class should declare at least one constructor +- 🟡 `pmd:UnusedPrivateField` L638 + Avoid unused private fields such as 'bad_name'. +- 🟡 `pmd:AtLeastOneConstructor` L642 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L643 + Missing commented default access modifier on method 'doIt(int)' +- 🟡 `pmd:AtLeastOneConstructor` L647 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L648 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:ForLoopShouldBeWhileLoop` L650 + This for loop could be simplified to a while loop +- 🟡 `pmd:AtLeastOneConstructor` L657 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L658 + Missing commented default access modifier on method 'bad(int)' +- 🟡 `pmd:AtLeastOneConstructor` L663 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L664 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:UnusedLocalVariable` L666 + Avoid unused local variables such as 'x'. +- 🟡 `pmd:IdenticalCatchBranches` L669 + 'catch' branch identical to 'ArithmeticException' branch +- 🟡 `pmd:AvoidCatchingGenericException` L669 + Avoid catching Exception in try-catch block +- 🟡 `pmd:AtLeastOneConstructor` L676 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L677 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:UnusedLocalVariable` L678 + Avoid unused local variables such as 'f'. +- 🟡 `pmd:LambdaCanBeMethodReference` L678 + Lambda expression could be written as a method reference: `String::length` +- 🟡 `pmd:AtLeastOneConstructor` L683 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L684 + Missing commented default access modifier on method 'isReady(String)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L684 + Parameter 's' is not assigned and could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L690 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L691 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L692 + Local variable 'x' could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L698 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L699 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L700 + Local variable 'bad_var' could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L706 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L707 + Missing commented default access modifier on method 'bad(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L707 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L713 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L714 + Missing commented default access modifier on method 'BadMethod()' +- 🟡 `pmd:AtLeastOneConstructor` L719 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L720 + Public member 'm' declared in a non-public type +- 🟡 `pmd:UnusedPrivateField` L722 + Avoid unused private fields such as 'x'. +- 🟡 `pmd:FieldDeclarationsShouldBeAtStartOfClass` L722 + Fields should be declared at the top of the class, before any method declarations, constructors, initializers or inner classes. +- 🟡 `pmd:FinalFieldCouldBeStatic` L722 + The final field x could be made static +- 🟡 `pmd:AtLeastOneConstructor` L726 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L727 + Missing commented default access modifier on method 'bad(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L727 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:OnlyOneReturn` L729 + A method should have only one exit point, and that should be the last statement in the method +- 🟡 `pmd:AtLeastOneConstructor` L736 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L737 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L738 + Local variable 'x' could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L746 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L747 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:AtLeastOneConstructor` L753 + Each class should declare at least one constructor +- 🟡 `pmd:AtLeastOneConstructor` L757 + Each class should declare at least one constructor +- 🟡 `pmd:UnnecessaryAnnotationValueElement` L758 + Avoid the use of value in annotations when its the only element +- 🟡 `pmd:CommentDefaultAccessModifier` L759 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:AtLeastOneConstructor` L764 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L765 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:UnnecessaryBlock` L766 + This block isn't necessary. +- 🟡 `pmd:UnusedLocalVariable` L767 + Avoid unused local variables such as 'x'. +- 🟡 `pmd:AtLeastOneConstructor` L773 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L774 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:UnusedLocalVariable` L775 + Avoid unused local variables such as 'i'. +- 🟡 `pmd:PrimitiveWrapperInstantiation` L775 + Do not use `new Integer(...)`, prefer `Integer.valueOf(...)` +- 🟡 `pmd:UnnecessaryBoxing` L775 + Unnecessary explicit boxing +- 🟡 `pmd:AtLeastOneConstructor` L780 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L781 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L782 + Local variable 'o' could be declared final +- 🟡 `pmd:UnusedLocalVariable` L783 + Avoid unused local variables such as 's'. +- 🟡 `pmd:UnnecessaryConstructor` L789 + Avoid unnecessary constructors - the compiler will generate these for you +- 🟡 `pmd:CommentDefaultAccessModifier` L789 + Missing commented default access modifier on constructor 'UnNeedCons()' +- 🟡 `pmd:AtLeastOneConstructor` L794 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L795 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:UnusedLocalVariable` L796 + Avoid unused local variables such as 's'. +- 🟡 `pmd:UnnecessaryModifier` L806 + Unnecessary modifiers 'public abstract' on method 'm': the method is declared in an interface type +- 🟡 `pmd:AtLeastOneConstructor` L810 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L811 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:UnnecessaryReturn` L813 + Unnecessary return statement +- 🟡 `pmd:AtLeastOneConstructor` L818 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L819 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L820 + Local variable 'x' could be declared final +- 🟡 `pmd:UnnecessarySemicolon` L820 + Unnecessary semicolon +- 🟡 `pmd:AtLeastOneConstructor` L826 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L827 + Missing commented default access modifier on field 'l' +- 🟡 `pmd:UseDiamondOperator` L827 + Explicit type arguments can be replaced by a diamond: `new ArrayList<>()` +- 🟡 `pmd:AtLeastOneConstructor` L831 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L832 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L833 + Local variable 'x' could be declared final +- 🟡 `pmd:UseExplicitTypes` L833 + Use Explicit Types +- 🟡 `pmd:AtLeastOneConstructor` L839 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L840 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L841 + Local variable 'x' could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L847 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L848 + Missing commented default access modifier on field 'x' +- 🟡 `pmd:CommentDefaultAccessModifier` L849 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L850 + Local variable 'y' could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L856 + Each class should declare at least one constructor +- 🟡 `pmd:UseShortArrayInitializer` L857 + Array initialization can be written shorter +- 🟡 `pmd:CommentDefaultAccessModifier` L857 + Missing commented default access modifier on field 'a' +- 🟡 `pmd:AtLeastOneConstructor` L861 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L862 + Missing commented default access modifier on field 'x' +- 🟡 `pmd:UseUnderscoresInNumericLiterals` L862 + Number 1000000 should separate every third digit with an underscore +- 🟡 `pmd:AtLeastOneConstructor` L866 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L867 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L868 + Local variable 'len' could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L874 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L875 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L876 + Local variable 'x' could be declared final +- 🟡 `pmd:UnnecessaryConstructor` L898 + Avoid unnecessary constructors - the compiler will generate these for you +- 🟡 `pmd:CommentDefaultAccessModifier` L898 + Missing commented default access modifier on constructor 'ParentFix()' +- 🟡 `pmd:UnnecessaryConstructor` L902 + Avoid unnecessary constructors - the compiler will generate these for you +- 🟡 `pmd:CommentDefaultAccessModifier` L902 + Missing commented default access modifier on constructor 'ChildFix()' +- 🟡 `pmd:AtLeastOneConstructor` L908 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L909 + Public member 'getLength' declared in a non-public type +- 🟡 `pmd:MethodArgumentCouldBeFinal` L909 + Parameter 'strings' is not assigned and could be declared final +- 🟡 `pmd:PrematureDeclaration` L910 + Declaration of 'length' can be moved closer to its usages +- 🟡 `pmd:OnlyOneReturn` L912 + A method should have only one exit point, and that should be the last statement in the method +- 🟡 `pmd:LocalVariableCouldBeFinal` L914 + Local variable 'str' could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L922 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L923 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:UnusedAssignment` L924 + The initializer for variable 'o' is never used (overwritten on line 925) +- 🟡 `pmd:UnnecessaryCast` L925 + Unnecessary cast (Object) +- 🟡 `pmd:AtLeastOneConstructor` L935 + Each class should declare at least one constructor +- 🟡 `pmd:AtLeastOneConstructor` L939 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L940 + Missing commented default access modifier on field 'otherFoo' +- 🟡 `pmd:UselessQualifiedThis` L940 + Useless qualified this usage in the same class. +- 🟡 `pmd:CommentDefaultAccessModifier` L941 + Missing commented default access modifier on method 'doSomething()' +- 🟡 `pmd:UselessQualifiedThis` L942 + Useless qualified this usage in the same class. +- 🟡 `pmd:AtLeastOneConstructor` L948 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L949 + Public member 'lengthSum' declared in a non-public type +- 🟡 `pmd:MethodArgumentCouldBeFinal` L949 + Parameter 'strings' is not assigned and could be declared final +- 🟡 `pmd:LocalVariableCouldBeFinal` L955 + Local variable 'str' could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L963 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L964 + Public member 'compute' declared in a non-public type +- 🟡 `pmd:AtLeastOneConstructor` L968 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L969 + Missing commented default access modifier on field 'count' +- 🟡 `pmd:CommentDefaultAccessModifier` L971 + Missing commented default access modifier on method 'isEnabled()' +- 🟡 `pmd:CommentDefaultAccessModifier` L975 + Missing commented default access modifier on method 'getCount()' +- 🟡 `pmd:CommentDefaultAccessModifier` L979 + Missing commented default access modifier on method 'computeSomething()' +- 🟡 `pmd:AtLeastOneConstructor` L995 + Each class should declare at least one constructor +- 🟡 `pmd:LinguisticNaming` L996 + Linguistics Antipattern - The field 'isReady' indicates linguistically it is a boolean, but it is 'int' +- 🟡 `pmd:CommentDefaultAccessModifier` L996 + Missing commented default access modifier on field 'isReady' +- 🟡 `pmd:LinguisticNaming` L998 + Linguistics Antipattern - The method 'isValid' indicates linguistically it returns a boolean, but it returns 'int' +- 🟡 `pmd:CommentDefaultAccessModifier` L998 + Missing commented default access modifier on method 'isValid()' +- 🟡 `pmd:AtLeastOneConstructor` L1004 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L1005 + Public member 'invalid' declared in a non-public type +- 🟡 `pmd:UnnecessaryConstructor` L1012 + Avoid unnecessary constructors - the compiler will generate these for you +- 🟡 `pmd:CommentDefaultAccessModifier` L1012 + Missing commented default access modifier on constructor 'ParentRemain()' +- 🟡 `pmd:UnnecessaryConstructor` L1016 + Avoid unnecessary constructors - the compiler will generate these for you +- 🟡 `pmd:CallSuperInConstructor` L1016 + It is a good practice to call super() in a constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1016 + Missing commented default access modifier on constructor 'ChildRemain()' +- 🟡 `pmd:AtLeastOneConstructor` L1022 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L1023 + Public member 'lengthSum' declared in a non-public type +- 🟡 `pmd:MethodArgumentCouldBeFinal` L1023 + Parameter 'strings' is not assigned and could be declared final +- 🟡 `pmd:VariableDeclarationUsageDistance` L1024 + Distance between declaration of 'length' and its first usage is 11, current threshold is 7 +- 🟡 `pmd:LocalVariableCouldBeFinal` L1035 + Local variable 'str' could be declared final +- 🔵 `pmd:UnnecessaryImport` L14 + Unused import 'java.nio.charset.StandardCharsets' +- 🔵 `pmd:UnnecessaryImport` L17 + Unused import 'java.util.Date' +- 🔵 `pmd:UnnecessaryImport` L22 + Unused import 'java.util.Iterator' +- 🔵 `pmd:UnnecessaryImport` L30 + Unused static import 'java.lang.Math.min' +- 🔵 `pmd:UnnecessaryImport` L31 + Unused static import 'java.lang.Math.abs' +- 🔵 `pmd:UnnecessaryImport` L32 + Unused static import 'java.lang.Math.sqrt' +- 🔵 `pmd:UnnecessaryImport` L33 + Unused static import 'java.lang.Math.pow' +- 🔵 `pmd:UnnecessaryImport` L34 + Unused static import 'java.lang.Math.floor' +- 🔵 `pmd:UnnecessaryImport` L35 + Unused static import 'java.lang.Math.ceil' +- 🔵 `pmd:UnnecessaryImport` L36 + Unused static import 'java.lang.Math.round' +- 🔵 `pmd:UnnecessaryImport` L37 + Unused static import 'java.lang.Math.random' +- 🔵 `pmd:UnnecessaryImport` L38 + Unused static import 'java.lang.Math.sin' +- 🔵 `pmd:UnnecessaryImport` L39 + Unused static import 'java.lang.Math.cos' +- 🔵 `pmd:UnnecessaryImport` L40 + Unused static import 'java.lang.Math.tan' +- 🔵 `pmd:UseVarargs` L59 + Consider using varargs for methods or constructors which take an array the last parameter. +- 🔵 `pmd:UseVarargs` L187 + Consider using varargs for methods or constructors which take an array the last parameter. +- 🔵 `pmd:OneDeclarationPerLine` L206 + Use one line for each declaration, it enhances code readability. +- 🔵 `pmd:UnnecessaryFullyQualifiedName` L487 + Unnecessary qualifier 'java.util': 'Enumeration' is already in scope because it is imported in this file +- 🔵 `pmd:BooleanGetMethodName` L576 + A getX() method which returns a boolean or Boolean should be named isX() +- 🔵 `pmd:ExtendsObject` L626 + No need to explicitly extend Object. +- 🔵 `pmd:TypeParameterNamingConventions` L753 + The type parameter name 'bad' doesn't match '[A-Z]' +- 🔵 `pmd:UnnecessaryFullyQualifiedName` L796 + Unnecessary qualifier 'java.lang': 'String' is already in scope because it is declared in java.lang +- 🔵 `pmd:UnnecessaryFullyQualifiedName` L796 + Unnecessary qualifier 'java.lang': 'String' is already in scope because it is declared in java.lang +- 🔵 `pmd:UselessParentheses` L841 + Useless parentheses around `1 + 2`. +- 🔵 `pmd:UseVarargs` L909 + Consider using varargs for methods or constructors which take an array the last parameter. +- 🔵 `pmd:UnnecessaryInterfaceDeclaration` L935 + Unnecessary interface declaration 'com.demo.bpcs.IBase', already provided by 'com.demo.bpcs.IExt'. +- 🔵 `pmd:UseVarargs` L949 + Consider using varargs for methods or constructors which take an array the last parameter. +- 🔵 `pmd:UseVarargs` L1023 + Consider using varargs for methods or constructors which take an array the last parameter. + +AI 审查 · 7 条建议 + +- 🔴 [AI] [bug] `null-statement-dereference` L268 + **RsDemo 中 Statement 为 null 却直接调用 executeQuery,必然触发 NullPointerException** + L267 将 Statement 变量 st 初始化为 null,L268 立即调用 st.executeQuery("select 1"),在没有任何赋值的情况下必然抛出 NullPointerException。静态分析只报告了资源未关闭和 ResultSet 返回值未检查,但未识别这个必然的空指针。 + 建议: 先通过 Connection.createStatement() 正确初始化 Statement,或在调用前判空并处理;也可直接使用 try-with-resources 管理 Statement 与 ResultSet。 +- 🟡 [AI] [bug] `incomplete-object-initialization` L71 + **Hasher 构造函数吞掉 MessageDigest 初始化异常,对象处于不一致状态** + Hasher 构造函数在 catch(Exception) 中仅记录日志,MessageDigest.getInstance("SHA-256") 失败时 digest 保持为 null。对象仍会被创建并返回给调用方,后续任何使用 digest 的操作都会触发 NullPointerException。应 fail-fast,让对象在构造失败时不可用。 + 建议: 将 digest 声明为 final,构造函数改为初始化失败时抛出 IllegalStateException(携带原始异常),或使用静态初始化块并在失败时抛出 ExceptionInInitializerError。 +- 🟡 [AI] [security] `hardcoded-ip-address` L93 + **NetConfig 中硬编码了 IP 地址,存在安全风险** + L93 的 host 字段硬编码了内网 IP "192.168.1.1"。硬编码 IP 会使代码难以在不同环境部署,且易被攻击者直接定位内网地址;若该值被提交到源码仓库,可能成为信息泄露点。静态分析结果未包含 AvoidUsingHardCodedIP 规则。 + 建议: 将主机地址改为从配置、环境变量或系统属性读取,并在启动时校验格式。 +- 🟡 [AI] [bug] `resource-leak-on-construction-failure` L176 + **链式构造缓冲读取器时,若中间构造失败将泄漏底层 FileInputStream** + L176 使用 new BufferedReader(new InputStreamReader(new FileInputStream("h.txt"))) 链式构造资源。若 InputStreamReader 或 BufferedReader 的构造函数抛出异常,已经成功打开的 FileInputStream 不会被关闭,因为此时还没有引用指向它。静态分析报告了 CloseResource 和 UseTryWithResources,但未指出链式构造本身是泄漏点。 + 建议: 使用 Files.newBufferedReader(Paths.get("h.txt"), StandardCharsets.UTF_8) 一步创建,或先用独立变量创建 FileInputStream 并放入 try-with-resources。 +- 🟡 [AI] [bug] `infinite-iteration` L490 + **EnumerationImpl 的 hasMoreElements() 永远返回 true,造成无限迭代** + EnumerationImpl 的 hasMoreElements() 恒为 true,而 nextElement() 每次使 i 自增并返回新字符串,导致枚举序列无限增长,最终 i 会溢出为负数。此外类声明使用了裸类型 java.util.Enumeration,未指定泛型参数,存在类型安全隐患。 + 建议: 为 hasMoreElements() 设置明确的终止条件(如 i < 10),并为 Enumeration 指定泛型参数(如 Enumeration),同时让 nextElement() 返回 String 类型。 +- 🔵 [AI] [style] `redundant-local-variable` L868 + **InlineVar 中局部变量 len 仅使用一次,可直接内联** + L868 声明的 int len = 5 只在 L869 使用一次,没有复用价值,属于冗余局部变量,增加阅读负担。静态分析未对 InlineVar 报告 VariableCanBeInlined。 + 建议: 删除 len 变量,直接将字面量 5 传给 System.out.println。 +- 🔵 [AI] [design] `misleading-getter` L975 + **getCount() 返回 computeSomething() 而非 count 字段,getter 语义误导** + L975 的 getCount() 方法名为获取 count 字段的 getter,实际却返回 computeSomething() 的计算结果(42)。调用方会误以为获取的是对象状态 count,但实际拿到的与字段无关,容易引入逻辑错误。静态分析仅报告了 L996/L998 的 LinguisticNaming,未覆盖此方法。 + 建议: 让 getCount() 返回 count 字段,或将方法重命名为 computeCount()/getComputedValue() 以准确表达语义。 diff --git a/data/demo-pmd/reports/CallSuperDemo-review.md b/data/demo-pmd/reports/CallSuperDemo-review.md new file mode 100644 index 0000000..189d4ef --- /dev/null +++ b/data/demo-pmd/reports/CallSuperDemo-review.md @@ -0,0 +1,46 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\errorprone\extra\CallSuperDemo.java` +**语言:** java +**耗时:** 104.2s +**分析工具:** pmd + +--- + +总计: 10 | 错误: 3 | 警告: 7 | 建议: 0 + +静态分析 · 7 个问题 + +- 🔴 `pmd:SystemPrintln` L34 + 使用了System.out/err + 建议: 在Android中应使用日志框架,例如用 android.util.Log.d("CallSuperMain", "demo call super") 替代 System.out.println,并确保导入 Log 类。 +- 🟡 `pmd:AtLeastOneConstructor` L11 + 每个类应至少声明一个构造函数 + 建议: 为类添加一个无参构造函数,并调用 super()。例如:public MissingSuperFirst() { super(); } +- 🟡 `pmd:CallSuperFirst` L13 + 应在方法开头调用super + 建议: 在onCreate方法的第一行调用 super.onCreate(bundle),然后再执行其他操作。 +- 🟡 `pmd:CommentDefaultAccessModifier` L17 + 方法'foo()'缺少默认访问修饰符的注释 + 建议: 为默认包私有访问权限添加注释,例如:/* default */ void foo();或者如果方法仅在类内部使用,可以显式声明为 private。 +- 🟡 `pmd:AtLeastOneConstructor` L22 + 每个类应至少声明一个构造函数 + 建议: 为类添加一个无参构造函数,并调用 super()。例如:public MissingSuperLast() { super(); } +- 🟡 `pmd:CallSuperLast` L24 + 应在方法末尾调用super + 建议: 在onPause方法的最后一行调用 super.onPause(),确保父类生命周期逻辑正确执行。 +- 🟡 `pmd:CommentDefaultAccessModifier` L28 + 方法'foo()'缺少默认访问修饰符的注释 + 建议: 为默认包私有访问权限添加注释,例如:/* default */ void foo();或者如果方法仅在类内部使用,可以显式声明为 private。 + +AI 审查 · 3 条建议 + +- 🔴 [AI] [bug] `activity-class-not-public` L11 + **Activity子类未声明为public** + 在Android中,Activity类必须声明为public,否则系统可能无法通过反射实例化并启动。MissingSuperFirst类当前为包私有,应在类声明中添加public修饰符。 +- 🔴 [AI] [bug] `activity-class-not-public` L22 + **Activity子类未声明为public** + MissingSuperLast类同样应声明为public,确保系统能够实例化。 +- 🟡 [AI] [design] `no-useless-main` L33 + **包含无用的main方法** + CallSuperMain类中的main方法在Android应用中不会作为入口执行,Android应用由Activity生命周期驱动。此方法可能是遗留代码或用于本地测试,建议删除或将其抽取到独立的测试类中使用JUnit进行测试。 diff --git a/data/demo-pmd/reports/DemoJsp-review.md b/data/demo-pmd/reports/DemoJsp-review.md new file mode 100644 index 0000000..53504a9 --- /dev/null +++ b/data/demo-pmd/reports/DemoJsp-review.md @@ -0,0 +1,72 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\jsp\DemoJsp.jsp` +**语言:** html +**耗时:** 239.9s +**分析工具:** jsp + +--- + +总计: 17 | 错误: 6 | 警告: 10 | 建议: 1 + +静态分析 · 12 个问题 + +- 🔴 `eslint:no-unused-vars` L18 + 第 18 行:'init' 已定义但从未使用。 + 建议: 若该函数用于页面初始化,应显式绑定 window.addEventListener('load', init); 否则删除整个 init 函数。 +- 🔴 `eslint:no-var` L19 + 第 19 行:不允许使用 var,请改用 let 或 const。 + 建议: x 声明后未再被赋值,应使用 const x = 1; 代替 var x = 1;。 +- 🔴 `eslint:no-undef` L20 + 第 20 行:'alert' 未定义。 + 建议: 在浏览器环境应使用 window.alert(x); 更明确;也可以添加 /* global alert */ 注释作为全局声明。 +- 🔴 `pmd:NoClassAttribute` L37 + 第 37 行:不要使用名为 class 的属性。 + 建议: 将 class="highlight" 改为 id="highlight"(并确保页面内 id 唯一),在外部 CSS 中使用 #highlight 定义样式。 +- 🟡 `pmd:NoScriptlets` L11 + 第 11 行:JSP 文件中应避免使用 scriptlet(Java 脚本片段)。 + 建议: 将脚本片段改为 JSTL/EL 表达式,例如输出“Hello ”,业务逻辑应放在控制器或后台 Bean 中;并记得声明 JSTL taglib。 +- 🟡 `pmd:LocalVariableCouldBeFinal` L12 + 第 12 行:局部变量 'name' 可声明为 final。 + 建议: 将 String name 改为 final String name = request.getParameter("name"); 更推荐移除 scriptlet,使用 输出。 +- 🟡 `pmd:NoInlineScript` L17 + 第 17 行:不要将 JavaScript 内容内联在 JSP/HTML 中。 + 建议: 将脚本移到独立的 .js 文件,例如 src="js/init.js",然后通过 引入;不要使用内联 script 块。 +- 🟡 `pmd:NoInlineStyleInformation` L25 + 第 25 行:避免在 JSP 文件中包含样式信息(

)。 + 建议: 移除 align 属性,改用外部 CSS,例如

,并在 CSS 中定义 #center-aligned { text-align: center; }。 +- 🟡 `pmd:NoInlineStyleInformation` L25 + 第 25 行:避免在 JSP 文件中包含样式信息( 加粗标签)。 + 建议: 用语义化的 Bold inline style 代替 ,或使用 CSS font-weight 设置加粗。 +- 🟡 `pmd:NoInlineStyleInformation` L25 + 第 25 行:避免在 JSP 文件中包含样式信息()。 + 建议: 将颜色样式移到外部 CSS,例如改为 Font inline style,并在 CSS 中定义 #font-inline-style-demo { color: red; }。 +- 🟡 `pmd:DontNestJsfInJstlIteration` L33 + 第 33 行:不要在会遍历 body 的 JSTL 迭代标签内嵌套 JSF 组件。 + 建议: 若迁移到 Facelets,使用 替代 c:forEach;否则请避免在 JSP 中混用 JSF 组件与 JSTL 迭代生命周期。 +- 🟡 `pmd:DuplicateJspImports` L42 + 第 42 行:java.util.List 被重复导入。 + 建议: 删除其中一个重复的 <%@ page import="java.util.List" %>,只保留一条导入语句。 + +AI 审查 · 5 条建议 + +- 🔴 [AI] [security] `reflected-xss` L13 + **反射型 XSS:用户参数未编码直接输出** + request.getParameter("name") 由用户控制,脚本中通过 out.println("Hello " + name) 直接拼入 HTML;当 name 含 等载荷时会被浏览器执行。 + 建议: 移除 scriptlet,改用 或 OWASP Java Encoder 对输出做 HTML 实体编码,杜绝 XSS。 +- 🔴 [AI] [bug] `missing-taglib-declaration` L32 + **缺少 JSTL/JSF 标签库声明** + 页面第 32-33 行使用了 ,但没有任何 <%@ taglib %> 指令声明 c 和 h 前缀;JSP 容器无法解析这些标签,会导致编译失败或运行时错误。 + 建议: 在页面顶部增加 JSTL Core 和 JSF HTML 标签库的 taglib 指令,命名空间 URI 根据实际 JSTL/JSF 版本调整。 +- 🟡 [AI] [style] `inline-style-attribute` L26 + **第 26 行存在未标记的内联样式属性** +

将样式写在 JSP 页面中,虽然 PMD 结果只标记了第 25 行的样式,但第 26 行同样违反内联样式外置的原则,也会增加维护成本。 + 建议: 移除 style 属性,将颜色样式写到外部 CSS 文件,例如
Inline style
,并在 CSS 中定义 #inline-style-demo { color: red; }。 +- 🟡 [AI] [bug] `jsf-el-value-expression` L33 + **JSF 组件值表达式应使用 #{} 而不是 ${}** + 第 33 行 在 JSF 组件中使用了 JSP EL ${}。JSF 的 ValueExpression 应使用 #{} 延迟求值,否则可能被当作普通字符串/文本解析,或无法正确解析 c:forEach 暴露的变量。 + 建议: 改为 ;若配合修复 DontNestJsfInJstlIteration,把外层 c:forEach 替换为 Facelets 的 ui:repeat。 +- 🔵 [AI] [design] `incomplete-html5-document` L5 + **HTML5 文档缺少 DOCTYPE 与 lang 属性** + 没有前置 ,也没有 lang 属性,可能导致浏览器以怪癖模式渲染,同时影响屏幕阅读器/SEO 对页面语言的识别。 + 建议: 在 前添加 ,并设置 (按实际内容语言调整)。 diff --git a/data/demo-pmd/reports/DesignErrorProne-review.md b/data/demo-pmd/reports/DesignErrorProne-review.md new file mode 100644 index 0000000..641eb22 --- /dev/null +++ b/data/demo-pmd/reports/DesignErrorProne-review.md @@ -0,0 +1,1707 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\designep\DesignErrorProne.java` +**语言:** java +**耗时:** 195.1s +**分析工具:** pmd + +--- + +总计: 771 | 错误: 166 | 警告: 598 | 建议: 7 + +静态分析 · 762 个问题 + +- 🔴 `pmd:AbstractClassWithoutAnyMethod` L30 + 抽象类没有抽象方法,abstract 可能只是用来阻止实例化 + 建议: 如果目的是阻止实例化,应使用私有或 protected 构造函数而非 abstract。 +- 🔴 `pmd:SystemPrintln` L39 + 使用了 System.out/err 输出 + 建议: 改用 SLF4J/Log4j 等日志框架记录输出。 +- 🔴 `pmd:AvoidThrowingNullPointerException` L75 + 避免手动抛出 NullPointerException + 建议: 应通过参数校验、Objects.requireNonNull 等方式处理,而不是直接 new NullPointerException。 +- 🔴 `pmd:AvoidThrowingRawExceptionTypes` L82 + 避免抛出原始异常类型 RuntimeException + 建议: 抛出自定义异常或更具体的异常类型,并携带业务上下文。 +- 🔴 `pmd:ClassWithOnlyPrivateConstructorsShouldBeFinal` L93 + 只有私有构造函数,应声明为 final + 建议: 给类添加 final 修饰符,防止通过反射或内部类扩展。 +- 🔴 `pmd:SystemPrintln` L103 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L140 + Usage of System.out/err +- 🔴 `pmd:FieldNamingConventions` L149 + 字段命名不符合约定 + 建议: 按 Java 命名规范:常量用 UPPER_SNAKE,普通字段用 lowerCamel。 +- 🔴 `pmd:SystemPrintln` L155 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L158 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L161 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L164 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L167 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L170 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L173 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L176 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L179 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L182 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L185 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L188 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L191 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L194 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L197 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L200 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L203 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L206 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L209 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L212 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L215 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L218 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L221 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L224 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L227 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L230 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L233 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L236 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L239 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L242 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L245 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L248 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L251 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L254 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L257 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L260 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L263 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L266 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L269 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L272 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L275 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L278 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L281 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L284 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L287 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L290 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L293 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L296 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L299 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L302 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L422 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L423 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L424 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L425 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L426 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L427 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L428 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L429 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L430 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L431 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L432 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L433 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L436 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L437 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L438 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L439 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L440 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L441 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L442 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L443 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L444 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L445 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L446 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L447 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L450 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L451 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L452 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L453 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L454 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L455 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L456 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L457 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L458 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L459 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L460 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L461 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L464 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L495 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L496 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L497 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L498 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L501 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L502 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L503 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L504 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L507 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L508 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L509 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L510 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L513 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L514 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L515 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L516 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L528 + Usage of System.out/err +- 🔴 `pmd:AvoidReassigningParameters` L538 + 避免重新为参数赋值 + 建议: 使用新的局部变量保存修改后的值。 +- 🔴 `pmd:SystemPrintln` L539 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L577 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L578 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L586 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L597 + Usage of System.out/err +- 🔴 `pmd:ConstructorCallsOverridableMethod` L693 + 构造函数中调用了可重写方法 + 建议: 避免在构造期间调用非 final/method,或将该方法设为 final/private。 +- 🔴 `pmd:DoNotCallGarbageCollectionExplicitly` L702 + 不要显式触发垃圾回收 + 建议: 删除 System.gc(),交由 JVM 自动管理内存。 +- 🔴 `pmd:AvoidThrowingRawExceptionTypes` L728 + Avoid throwing raw exception type RuntimeException. +- 🔴 `pmd:EqualsNull` L758 + 避免使用 equals() 与 null 比较 + 建议: 使用 o == null 判空,而不是 o.equals(null)。 +- 🔴 `pmd:AvoidReassigningParameters` L766 + Avoid reassigning parameters such as 's' +- 🔴 `pmd:SystemPrintln` L768 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L788 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L790 + Usage of System.out/err +- 🔴 `pmd:MethodNamingConventions` L816 + 方法命名不符合约定 + 建议: 使用 lowerCamelCase 命名方法,如 sameName()。 +- 🔴 `pmd:ClassWithOnlyPrivateConstructorsShouldBeFinal` L829 + This class has only private constructors and may be final +- 🔴 `pmd:MoreThanOneLogger` L835 + 类中包含多个 logger + 建议: 统一使用一个 logger 实例,避免日志输出混乱。 +- 🔴 `pmd:SystemPrintln` L843 + Usage of System.out/err +- 🔴 `pmd:ReturnEmptyCollectionRatherThanNull` L882 + 应返回空集合而不是 null + 建议: 返回 Collections.emptyList() 或 List.of()。 +- 🔴 `pmd:SuspiciousEqualsMethodName` L909 + 方法名与 equals(Object) 高度相似,容易误导 + 建议: 重命名方法,或改为真正重写 equals(Object)。 +- 🔴 `pmd:SystemPrintln` L928 + Usage of System.out/err +- 🔴 `pmd:FieldNamingConventions` L996 + The field name 'TypeName' doesn't match '[a-z][a-zA-Z0-9]*' +- 🔴 `pmd:SingleMethodSingleton` L1029 + 类包含多个 getInstance 方法,单例模式混乱 + 建议: 只保留一个无参 getInstance(),移除重载方法。 +- 🔴 `pmd:ClassWithOnlyPrivateConstructorsShouldBeFinal` L1029 + This class has only private constructors and may be final +- 🔴 `pmd:SingletonClassReturningNewInstance` L1039 + getInstance 总是创建新对象,不符合单例行为 + 建议: getInstance 应返回缓存的唯一实例,而不是新建对象。 +- 🔴 `pmd:SystemPrintln` L1070 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1078 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1089 + Usage of System.out/err +- 🔴 `pmd:FieldNamingConventions` L1096 + The constant name '_LOG' doesn't match '[A-Z][A-Z_0-9]*' +- 🔴 `pmd:GuardLogStatement` L1101 + 日志调用应使用日志级别守卫包裹 + 建议: 添加 if (LOGGER.isDebugEnabled()) 等守卫,或使用占位符避免字符串拼接。 +- 🔴 `pmd:SystemPrintln` L1134 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1178 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1208 + Usage of System.out/err +- 🔴 `pmd:SystemPrintln` L1218 + Usage of System.out/err +- 🔴 `pmd:AvoidBranchingStatementAsLastInLoop` L1222 + 避免在循环末尾使用 break/continue 作为最后一条语句 + 建议: 调整循环结构,使正常退出条件更明确。 +- 🔴 `pmd:AvoidMultipleUnaryOperators` L1230 + 多个一元运算符叠用可能造成误解或 bug + 建议: 简化表达式,只保留一个运算符或使用括号明确语义。 +- 🔴 `pmd:AvoidMultipleUnaryOperators` L1231 + Using multiple unary operators may be a bug, and/or is confusing. +- 🔴 `pmd:SystemPrintln` L1232 + Usage of System.out/err +- 🔴 `pmd:BrokenNullCheck` L1239 + null 检查逻辑有误,可能导致 NullPointerException 或逻辑错误 + 建议: 检查短路语义:判空应使用 && 或 || 正确组合,并在空值分支避免解引用。 +- 🔴 `pmd:BrokenNullCheck` L1242 + Dereferencing the qualifier of this expression will throw a NullPointerException +- 🔴 `pmd:ProperCloneImplementation` L1254 + clone() 应通过 super.clone() 实现 + 建议: 使用 super.clone() 并强制转换返回类型,而不是 new 新对象。 +- 🔴 `pmd:ProperCloneImplementation` L1286 + Object clone() should be implemented with super.clone() +- 🔴 `pmd:FieldNamingConventions` L1339 + The field name 'LOG' doesn't match '[a-z][a-zA-Z0-9]*' +- 🔴 `pmd:FieldNamingConventions` L1344 + The constant name '_LOG' doesn't match '[A-Z][A-Z_0-9]*' +- 🔴 `pmd:ClassWithOnlyPrivateConstructorsShouldBeFinal` L1372 + This class has only private constructors and may be final +- 🔴 `pmd:FieldNamingConventions` L1373 + The static field name 'INSTANCE' doesn't match '[a-z][a-zA-Z0-9]*' +- 🔴 `pmd:ClassWithOnlyPrivateConstructorsShouldBeFinal` L1384 + This class has only private constructors and may be final +- 🔴 `pmd:FieldNamingConventions` L1385 + The static field name 'INSTANCE' doesn't match '[a-z][a-zA-Z0-9]*' +- 🔴 `pmd:SystemPrintln` L1400 + Usage of System.out/err +- 🟡 `pmd:AtLeastOneConstructor` L30 + 每个类应至少声明一个构造函数(适用于所有命中项) + 建议: 为没有构造函数的类添加显式构造函数;若类不应被实例化,则改为私有构造。 +- 🟡 `pmd:AbstractClassWithoutAbstractMethod` L30 + 该抽象类没有任何抽象方法 + 建议: 删除 abstract 关键字,或为类增加抽象方法。 +- 🟡 `pmd:AtLeastOneConstructor` L34 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L35 + 缺少默认访问修饰符的注释(方法/字段/类) + 建议: 为包级私有成员添加 /* default */ 注释,或显式声明 private/protected/public。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L35 + 参数未被赋值,可以声明为 final(适用于所有命中项) + 建议: 在方法参数前添加 final 修饰符,避免无意中重新赋值。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L35 + Parameter 'b' is not assigned and could be declared final +- 🟡 `pmd:MethodArgumentCouldBeFinal` L35 + Parameter 'c' is not assigned and could be declared final +- 🟡 `pmd:CollapsibleIfStatements` L37 + 该 if 语句可以与父级 if 合并 + 建议: 使用 && 或 || 将嵌套条件合并,减少嵌套层级。 +- 🟡 `pmd:AvoidDeeplyNestedIfStmts` L38 + if 嵌套过深,难以阅读 + 建议: 使用卫语句、提前返回或提取方法降低嵌套深度。 +- 🟡 `pmd:CollapsibleIfStatements` L38 + This if statement could be combined with its parent +- 🟡 `pmd:AtLeastOneConstructor` L47 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L48 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:AvoidRethrowingException` L51 + 捕获异常后仅重新抛出,应避免 + 建议: 不要捕获该异常,直接在方法签名中声明抛出;若必须捕获,请加入实际处理逻辑。 +- 🟡 `pmd:CommentDefaultAccessModifier` L55 + Missing commented default access modifier on method 'doWork()' +- 🟡 `pmd:AtLeastOneConstructor` L60 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L61 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:CommentDefaultAccessModifier` L68 + Missing commented default access modifier on method 'doWork()' +- 🟡 `pmd:AtLeastOneConstructor` L73 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L74 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:AtLeastOneConstructor` L80 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L81 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:AtLeastOneConstructor` L87 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L88 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:AvoidUncheckedExceptionsInSignatures` L88 + 方法/构造函数不应显式声明非受检异常 RuntimeException + 建议: 从 throws 子句中删除非受检异常。 +- 🟡 `pmd:MissingStaticMethodInNonInstantiatableClass` L93 + 类无法实例化,且没有提供任何静态方法或字段 + 建议: 添加 public static 方法/工厂方法,或将类声明为 final 并仅作工具类使用。 +- 🟡 `pmd:AtLeastOneConstructor` L99 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L100 + Missing commented default access modifier on method 'bad(int, int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L100 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:MethodArgumentCouldBeFinal` L100 + Parameter 'b' is not assigned and could be declared final +- 🟡 `pmd:CollapsibleIfStatements` L102 + This if statement could be combined with its parent +- 🟡 `pmd:AtLeastOneConstructor` L110 + Each class should declare at least one constructor +- 🟡 `pmd:DataClass` L110 + 类疑似数据类(只包含 getter/setter) + 建议: 将数据与行为封装在一起,增加业务方法,避免仅作为数据容器。 +- 🟡 `pmd:PublicMemberInNonPublicType` L113 + 非公共类型中声明了公共成员 + 建议: 将类改为 public,或将该成员的访问级别降为 package 私有。 +- 🟡 `pmd:PublicMemberInNonPublicType` L116 + Public member 'setName' declared in a non-public type +- 🟡 `pmd:MethodArgumentCouldBeFinal` L116 + Parameter 'name' is not assigned and could be declared final +- 🟡 `pmd:PublicMemberInNonPublicType` L119 + Public member 'getAge' declared in a non-public type +- 🟡 `pmd:PublicMemberInNonPublicType` L122 + Public member 'setAge' declared in a non-public type +- 🟡 `pmd:MethodArgumentCouldBeFinal` L122 + Parameter 'age' is not assigned and could be declared final +- 🟡 `pmd:MissingSerialVersionUID` L128 + 实现 Serializable 的类应定义 serialVersionUID + 建议: 添加 private static final long serialVersionUID = 1L; +- 🟡 `pmd:AtLeastOneConstructor` L128 + Each class should declare at least one constructor +- 🟡 `pmd:DoNotExtendJavaLangError` L128 + 异常不应继承 java.lang.Error + 建议: 应继承 Exception/RuntimeException,Error 留给 JVM 内部严重错误。 +- 🟡 `pmd:AtLeastOneConstructor` L132 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L133 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:UnusedAssignment` L134 + 变量的初始值从未被使用 + 建议: 删除初始赋值,或直接使用最终需要的值初始化。 +- 🟡 `pmd:CommentDefaultAccessModifier` L142 + Missing commented default access modifier on method 'check()' +- 🟡 `pmd:AtLeastOneConstructor` L148 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L149 + Missing commented default access modifier on field 'CONST' +- 🟡 `pmd:FinalFieldCouldBeStatic` L149 + final 字段可以声明为 static + 建议: 若字段是编译时常量,请声明为 static final。 +- 🟡 `pmd:AtLeastOneConstructor` L153 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L154 + Missing commented default access modifier on method 'm1(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L154 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L157 + Missing commented default access modifier on method 'm2(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L157 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L160 + Missing commented default access modifier on method 'm3(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L160 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L163 + Missing commented default access modifier on method 'm4(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L163 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L166 + Missing commented default access modifier on method 'm5(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L166 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L169 + Missing commented default access modifier on method 'm6(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L169 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L172 + Missing commented default access modifier on method 'm7(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L172 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L175 + Missing commented default access modifier on method 'm8(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L175 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L178 + Missing commented default access modifier on method 'm9(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L178 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L181 + Missing commented default access modifier on method 'm10(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L181 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L184 + Missing commented default access modifier on method 'm11(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L184 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L187 + Missing commented default access modifier on method 'm12(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L187 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L190 + Missing commented default access modifier on method 'm13(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L190 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L193 + Missing commented default access modifier on method 'm14(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L193 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L196 + Missing commented default access modifier on method 'm15(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L196 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L199 + Missing commented default access modifier on method 'm16(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L199 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L202 + Missing commented default access modifier on method 'm17(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L202 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L205 + Missing commented default access modifier on method 'm18(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L205 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L208 + Missing commented default access modifier on method 'm19(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L208 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L211 + Missing commented default access modifier on method 'm20(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L211 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L214 + Missing commented default access modifier on method 'm21(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L214 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L217 + Missing commented default access modifier on method 'm22(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L217 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L220 + Missing commented default access modifier on method 'm23(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L220 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L223 + Missing commented default access modifier on method 'm24(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L223 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L226 + Missing commented default access modifier on method 'm25(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L226 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L229 + Missing commented default access modifier on method 'm26(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L229 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L232 + Missing commented default access modifier on method 'm27(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L232 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L235 + Missing commented default access modifier on method 'm28(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L235 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L238 + Missing commented default access modifier on method 'm29(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L238 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L241 + Missing commented default access modifier on method 'm30(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L241 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L244 + Missing commented default access modifier on method 'm31(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L244 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L247 + Missing commented default access modifier on method 'm32(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L247 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L250 + Missing commented default access modifier on method 'm33(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L250 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L253 + Missing commented default access modifier on method 'm34(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L253 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L256 + Missing commented default access modifier on method 'm35(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L256 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L259 + Missing commented default access modifier on method 'm36(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L259 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L262 + Missing commented default access modifier on method 'm37(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L262 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L265 + Missing commented default access modifier on method 'm38(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L265 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L268 + Missing commented default access modifier on method 'm39(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L268 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L271 + Missing commented default access modifier on method 'm40(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L271 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L274 + Missing commented default access modifier on method 'm41(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L274 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L277 + Missing commented default access modifier on method 'm42(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L277 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L280 + Missing commented default access modifier on method 'm43(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L280 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L283 + Missing commented default access modifier on method 'm44(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L283 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L286 + Missing commented default access modifier on method 'm45(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L286 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L289 + Missing commented default access modifier on method 'm46(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L289 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L292 + Missing commented default access modifier on method 'm47(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L292 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L295 + Missing commented default access modifier on method 'm48(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L295 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L298 + Missing commented default access modifier on method 'm49(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L298 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:CommentDefaultAccessModifier` L301 + Missing commented default access modifier on method 'm50(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L301 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:UnusedPrivateField` L308 + 存在未使用的私有字段 + 建议: 删除该字段,或确认其确实被需要后补充使用。 +- 🟡 `pmd:ImmutableField` L308 + 字段可以声明为 final + 建议: 初始化后不再变更的字段应添加 final 修饰符。 +- 🟡 `pmd:UnnecessaryConstructor` L310 + 构造函数不必要,编译器会生成默认构造 + 建议: 删除空的、无实际逻辑的构造函数。 +- 🟡 `pmd:CommentDefaultAccessModifier` L310 + Missing commented default access modifier on constructor 'Immut()' +- 🟡 `pmd:AtLeastOneConstructor` L315 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L317 + Public member 'getname' declared in a non-public type +- 🟡 `pmd:PublicMemberInNonPublicType` L320 + Public member 'setname' declared in a non-public type +- 🟡 `pmd:MethodArgumentCouldBeFinal` L320 + Parameter 'n' is not assigned and could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L326 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L327 + Missing commented default access modifier on method 'bad(A)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L327 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:LawOfDemeter` L328 + Call to `getB` on foreign value `a` (degree 1) +- 🟡 `pmd:AtLeastOneConstructor` L330 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L330 + Missing commented default access modifier on nested class 'A' +- 🟡 `pmd:CommentDefaultAccessModifier` L331 + Missing commented default access modifier on method 'getB()' +- 🟡 `pmd:AtLeastOneConstructor` L335 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L335 + Missing commented default access modifier on nested class 'B' +- 🟡 `pmd:CommentDefaultAccessModifier` L336 + Missing commented default access modifier on method 'getC()' +- 🟡 `pmd:AtLeastOneConstructor` L340 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L340 + Missing commented default access modifier on nested class 'C' +- 🟡 `pmd:CommentDefaultAccessModifier` L341 + Missing commented default access modifier on method 'doIt()' +- 🟡 `pmd:AtLeastOneConstructor` L347 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L348 + Missing commented default access modifier on method 'bad(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L348 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:SimplifyBooleanReturns` L349 + 该 if 语句可被替换为返回条件表达式 + 建议: 例如 if (x) return true; else return false 应改为 return x; +- 🟡 `pmd:LogicInversion` L349 + Use opposite operator instead of the logic complement operator. +- 🟡 `pmd:OnlyOneReturn` L350 + 方法应只有唯一出口,且应在最后一条语句 + 建议: 将多个 return 改为单出口风格,或使用表达式结果返回。 +- 🟡 `pmd:UseUtilityClass` L359 + 所有成员都是静态的,应添加私有构造防止实例化 + 建议: 为工具类添加 private 无参构造函数,并将类声明为 final。 +- 🟡 `pmd:MutableStaticState` L360 + 不要使用非 final 非私有的静态字段 + 建议: 改为 private static final,或通过 getter/setter 控制访问。 +- 🟡 `pmd:CommentDefaultAccessModifier` L360 + Missing commented default access modifier on field 'counter' +- 🟡 `pmd:AtLeastOneConstructor` L364 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L365 + Public member 'x' declared in a non-public type +- 🟡 `pmd:AtLeastOneConstructor` L369 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L370 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:SignatureDeclareThrowsException` L370 + 方法/构造函数不应显式抛出 java.lang.Exception + 建议: 抛出具体异常类型,避免宽泛的 Exception。 +- 🟡 `pmd:AtLeastOneConstructor` L375 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L376 + Missing commented default access modifier on method 'bad(boolean)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L376 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:SimplifiedTernary` L377 + 三元表达式可以简化 + 建议: 例如 return x ? true : false 应改为 return x。 +- 🟡 `pmd:AtLeastOneConstructor` L382 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L383 + Missing commented default access modifier on method 'bad(boolean)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L383 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:SimplifyBooleanExpressions` L384 + 布尔表达式包含不必要的比较 + 建议: 例如 return x == true 应改为 return x。 +- 🟡 `pmd:AtLeastOneConstructor` L389 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L390 + Missing commented default access modifier on method 'bad(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L390 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:SimplifyBooleanReturns` L391 + This if statement can be replaced by `return {condition};` +- 🟡 `pmd:OnlyOneReturn` L392 + A method should have only one exit point, and that should be the last statement in the method +- 🟡 `pmd:AtLeastOneConstructor` L400 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L401 + Missing commented default access modifier on method 'bar(Object)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L401 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:EmptyControlStatement` L402 + 存在空的控制语句(if/for/while 等) + 建议: 补充逻辑或删除空语句块。 +- 🟡 `pmd:SimplifyConditional` L402 + instanceof 前不需要检查 null + 建议: 删除 x != null &&,因为 x instanceof List 已覆盖 null 情况。 +- 🟡 `pmd:AtLeastOneConstructor` L408 + Each class should declare at least one constructor +- 🟡 `pmd:SingularField` L409 + 字段可能应改为局部变量 + 建议: 如果字段只在一个方法中使用,请改为方法内局部变量。 +- 🟡 `pmd:PublicMemberInNonPublicType` L411 + Public member 'foo' declared in a non-public type +- 🟡 `pmd:MethodArgumentCouldBeFinal` L411 + Parameter 'y' is not assigned and could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L418 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L419 + Missing commented default access modifier on method 'bad(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L419 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:SwitchDensity` L420 + switch 中语句与分支比例过高 + 建议: 将每个 case 的逻辑抽取为独立方法,或使用多态/映射表重构。 +- 🟡 `pmd:AtLeastOneConstructor` L471 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L472 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:AtLeastOneConstructor` L475 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L477 + Missing commented default access modifier on method 'm()' +- 🟡 `pmd:UselessOverridingMethod` L477 + 重写方法仅调用 super,无实际用途 + 建议: 删除该重写方法,让父类方法直接生效。 +- 🟡 `pmd:UseUtilityClass` L483 + All members are static. Consider adding a private no-args constructor to prevent instantiation. +- 🟡 `pmd:CommentDefaultAccessModifier` L484 + Missing commented default access modifier on method 'helper()' +- 🟡 `pmd:AtLeastOneConstructor` L491 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L492 + Public member 'bar' declared in a non-public type +- 🟡 `pmd:MethodArgumentCouldBeFinal` L492 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L525 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L526 + Missing commented default access modifier on method 'bar(Object, String)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L526 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:MethodArgumentCouldBeFinal` L526 + Parameter 'baz' is not assigned and could be declared final +- 🟡 `pmd:MisplacedNullCheck` L527 + null 检查位置错误,可能引发 NullPointerException + 建议: 先判空再调用方法,例如 a != null && a.equals(baz)。 +- 🟡 `pmd:AtLeastOneConstructor` L536 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L537 + Missing commented default access modifier on method 'bad(int)' +- 🟡 `pmd:AssignmentInOperand` L538 + 避免在操作数中赋值 + 建议: 将赋值移到表达式外,单独一行,再参与判断。 +- 🟡 `pmd:UseUtilityClass` L545 + All members are static. Consider adding a private no-args constructor to prevent instantiation. +- 🟡 `pmd:MutableStaticState` L546 + Do not use non-final non-private static fields +- 🟡 `pmd:CommentDefaultAccessModifier` L546 + Missing commented default access modifier on field 'counter' +- 🟡 `pmd:CommentDefaultAccessModifier` L548 + Missing commented default access modifier on constructor 'AssignStatic()' +- 🟡 `pmd:AssignmentToNonFinalStatic` L549 + 构造函数中给非 final 静态字段赋值可能不安全 + 建议: 使用实例字段,或通过 static final/初始化块管理静态状态。 +- 🟡 `pmd:AtLeastOneConstructor` L554 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L555 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:SignatureDeclareThrowsException` L555 + A method/constructor should not explicitly throw java.lang.Exception +- 🟡 `pmd:LocalVariableCouldBeFinal` L556 + 局部变量可声明为 final + 建议: 为只赋值一次的局部变量添加 final 修饰符。 +- 🟡 `pmd:AvoidAccessibilityAlteration` L557 + 不应使用 setAccessible(true) 修改可见性 + 建议: 避免反射破坏封装;若必须,应评估安全风险并限制调用权限。 +- 🟡 `pmd:AtLeastOneConstructor` L562 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L563 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L564 + Local variable 'o' could be declared final +- 🟡 `pmd:AvoidCallingFinalize` L565 + 避免显式调用 finalize() 方法 + 建议: 删除显式调用,改用 try-with-resources 或 Cleaner 管理资源。 +- 🟡 `pmd:AtLeastOneConstructor` L570 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L571 + Missing commented default access modifier on field 'd' +- 🟡 `pmd:AvoidDecimalLiteralsInBigDecimalConstructor` L571 + 避免用浮点字面量构造 BigDecimal,可能产生精度问题 + 建议: 使用字符串构造:new BigDecimal("0.1")。 +- 🟡 `pmd:AtLeastOneConstructor` L575 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L576 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:AtLeastOneConstructor` L583 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L584 + Missing commented default access modifier on method 'bad(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L584 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:AvoidLiteralsInIfCondition` L585 + if 条件中避免使用魔术数字/字面量 + 建议: 将 42、5 等常量提取为命名常量。 +- 🟡 `pmd:AtLeastOneConstructor` L592 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L593 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:AssignmentInOperand` L596 + Avoid assignment to x in operand +- 🟡 `pmd:AtLeastOneConstructor` L602 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L603 + Missing commented default access modifier on field 'x' +- 🟡 `pmd:AvoidUsingOctalValues` L603 + 避免使用八进制字面量 + 建议: 去掉前导 0,或明确使用 0x/0b 前缀。 +- 🟡 `pmd:AtLeastOneConstructor` L607 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L608 + Missing commented default access modifier on method 'bad(Object, Object)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L608 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:MethodArgumentCouldBeFinal` L608 + Parameter 'b' is not assigned and could be declared final +- 🟡 `pmd:EmptyControlStatement` L609 + Empty if statement +- 🟡 `pmd:AtLeastOneConstructor` L615 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L616 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:UselessPureMethodCall` L618 + 调用了纯方法但未使用结果 + 建议: 删除该调用,或将结果赋给变量并使用。 +- 🟡 `pmd:CommentDefaultAccessModifier` L620 + Missing commented default access modifier on method 'doSomething()' +- 🟡 `pmd:AtLeastOneConstructor` L625 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L626 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:UselessPureMethodCall` L627 + Do not call pure method toString if the result is not used. +- 🟡 `pmd:CommentDefaultAccessModifier` L630 + Missing commented default access modifier on method 'doSomething()' +- 🟡 `pmd:AtLeastOneConstructor` L635 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L636 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:CloseResource` L637 + 资源使用后应关闭 + 建议: 使用 try-with-resources 自动关闭 InputStream 等资源。 +- 🟡 `pmd:LocalVariableCouldBeFinal` L637 + Local variable 'in' could be declared final +- 🟡 `pmd:CheckSkipResult` L638 + 应检查 InputStream.skip() 的返回值 + 建议: 将 skip 返回值赋给变量,并判断是否满足所需跳过字节数。 +- 🟡 `pmd:AtLeastOneConstructor` L643 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L644 + Missing commented default access modifier on method 'bad(Collection)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L644 + Parameter 'c' is not assigned and could be declared final +- 🟡 `pmd:UnusedLocalVariable` L645 + 存在未使用的局部变量 + 建议: 删除未使用的局部变量,或补全其使用逻辑。 +- 🟡 `pmd:ClassCastExceptionWithToArray` L645 + Collection.toArray() 的使用会抛出 ClassCastException + 建议: 使用 c.toArray(new String[0]) 传入类型化数组。 +- 🟡 `pmd:AtLeastOneConstructor` L650 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L651 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L652 + Local variable 'in' could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L658 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L659 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:UnusedLocalVariable` L660 + Avoid unused local variables such as 'l'. +- 🟡 `pmd:UnusedLocalVariable` L661 + Avoid unused local variables such as 'o'. +- 🟡 `pmd:PrimitiveWrapperInstantiation` L661 + 不要使用 new Integer(...),应使用 Integer.valueOf(...) + 建议: 使用装箱缓存或 Integer.valueOf 替代 new Integer。 +- 🟡 `pmd:UnnecessaryBoxing` L661 + 存在不必要的显式装箱 + 建议: 直接使用基本类型或依赖自动装箱。 +- 🟡 `pmd:AtLeastOneConstructor` L666 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L667 + Missing commented default access modifier on method 'bad(String, String)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L667 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:MethodArgumentCouldBeFinal` L667 + Parameter 'b' is not assigned and could be declared final +- 🟡 `pmd:EmptyControlStatement` L668 + Empty if statement +- 🟡 `pmd:CompareObjectsWithEquals` L668 + 比较对象引用应使用 equals() 而不是 == + 建议: 对非基本类型对象比较使用 equals()。 +- 🟡 `pmd:UseEqualsToCompareStrings` L668 + 比较字符串应使用 equals() 而不是 == + 建议: 使用 a.equals(b),并按需调用 equalsIgnoreCase。 +- 🟡 `pmd:AtLeastOneConstructor` L674 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L675 + Missing commented default access modifier on method 'bad(double)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L675 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:EmptyControlStatement` L676 + Empty if statement +- 🟡 `pmd:ComparisonWithNaN` L676 + 与 NaN 比较恒为 false + 建议: 使用 Double.isNaN(x) 判断 NaN。 +- 🟡 `pmd:AtLeastOneConstructor` L682 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L683 + Missing commented default access modifier on method 'call()' +- 🟡 `pmd:CommentDefaultAccessModifier` L686 + Missing commented default access modifier on method 'accept(String[])' +- 🟡 `pmd:CommentDefaultAccessModifier` L692 + Missing commented default access modifier on constructor 'CtorCall()' +- 🟡 `pmd:CommentDefaultAccessModifier` L695 + Missing commented default access modifier on method 'overridable()' +- 🟡 `pmd:AtLeastOneConstructor` L700 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L701 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:MissingSerialVersionUID` L707 + Classes implementing Serializable should set a serialVersionUID +- 🟡 `pmd:AtLeastOneConstructor` L707 + Each class should declare at least one constructor +- 🟡 `pmd:DoNotExtendJavaLangThrowable` L707 + 异常不应直接继承 java.lang.Throwable + 建议: 应继承 Exception 或 RuntimeException。 +- 🟡 `pmd:AtLeastOneConstructor` L711 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L712 + Missing commented default access modifier on field 'path' +- 🟡 `pmd:DoNotHardCodeSDCard` L712 + 不要硬编码 /sdcard 路径 + 建议: 使用环境变量或上下文 API 获取存储路径。 +- 🟡 `pmd:AtLeastOneConstructor` L716 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L717 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:DoNotTerminateVM` L718 + 不应调用 System.exit() 终止 JVM + 建议: 通过受控方式结束应用,或抛出异常交给上层处理。 +- 🟡 `pmd:AtLeastOneConstructor` L723 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L724 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:CommentDefaultAccessModifier` L731 + Missing commented default access modifier on method 'doWork()' +- 🟡 `pmd:AtLeastOneConstructor` L736 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L737 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:DontUseFloatTypeForLoopIndices` L738 + 不要使用浮点类型作为循环索引,浮点精度可能导致循环异常 + 建议: 改用 int/long 循环变量,或使用 double 并明确终止条件。 +- 🟡 `pmd:EmptyControlStatement` L738 + Empty for statement +- 🟡 `pmd:AtLeastOneConstructor` L744 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L745 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:EmptyCatchBlock` L748 + 避免空 catch 块 + 建议: 至少记录日志或做降级处理,不要静默吞掉异常。 +- 🟡 `pmd:AvoidCatchingGenericException` L748 + 避免捕获泛化 Exception + 建议: 捕获具体异常类型,如 IOException、IllegalArgumentException。 +- 🟡 `pmd:CommentDefaultAccessModifier` L751 + Missing commented default access modifier on method 'doWork()' +- 🟡 `pmd:AtLeastOneConstructor` L756 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L757 + Missing commented default access modifier on method 'bad(Object)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L757 + Parameter 'o' is not assigned and could be declared final +- 🟡 `pmd:EmptyControlStatement` L758 + Empty if statement +- 🟡 `pmd:AtLeastOneConstructor` L764 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L765 + Missing commented default access modifier on method 'bad(String)' +- 🟡 `pmd:AtLeastOneConstructor` L773 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L774 + Missing commented default access modifier on method 'bad(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L774 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:IdenticalConditionalBranches` L775 + 条件分支完全相同,条件判断无意义 + 建议: 删除 if/else,直接返回相同结果或提取公共逻辑。 +- 🟡 `pmd:OnlyOneReturn` L776 + A method should have only one exit point, and that should be the last statement in the method +- 🟡 `pmd:AtLeastOneConstructor` L784 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L785 + Missing commented default access modifier on method 'bad(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L785 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:ImplicitSwitchFallThrough` L789 + switch 分支存在隐式 fall-through + 建议: 在 case 末尾补上 break/return,或添加注释明确故意 fall-through。 +- 🟡 `pmd:AtLeastOneConstructor` L799 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L800 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:UnusedLocalVariable` L801 + Avoid unused local variables such as 'c'. +- 🟡 `pmd:PrimitiveWrapperInstantiation` L801 + Do not use `new Integer(...)`, prefer `Integer.valueOf(...)` +- 🟡 `pmd:AtLeastOneConstructor` L806 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L807 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:ForLoopVariableCount` L808 + for 循环中控制变量过多 + 建议: 拆分循环或将额外变量移到循环外,保持循环头简洁。 +- 🟡 `pmd:AvoidReassigningLoopVariables` L809 + 避免修改循环控制变量 + 建议: 不要在循环体内或内层循环更新外层循环变量,使用独立变量。 +- 🟡 `pmd:AtLeastOneConstructor` L815 + Each class should declare at least one constructor +- 🟡 `pmd:MethodWithSameNameAsEnclosingClass` L816 + 方法与包含它的类同名(可能误当构造函数) + 建议: 重命名方法,避免与类名混淆。 +- 🟡 `pmd:CommentDefaultAccessModifier` L816 + Missing commented default access modifier on method 'SameName()' +- 🟡 `pmd:AtLeastOneConstructor` L821 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L822 + Missing commented default access modifier on method 'bad(String)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L822 + Parameter 's' is not assigned and could be declared final +- 🟡 `pmd:EmptyControlStatement` L823 + Empty if statement +- 🟡 `pmd:MissingStaticMethodInNonInstantiatableClass` L829 + Class cannot be instantiated and does not provide any static methods or fields +- 🟡 `pmd:UnusedPrivateField` L836 + Avoid unused private fields such as 'LOG1'. +- 🟡 `pmd:UnusedPrivateField` L837 + Avoid unused private fields such as 'LOG2'. +- 🟡 `pmd:AtLeastOneConstructor` L841 + Each class should declare at least one constructor +- 🟡 `pmd:NonStaticInitializer` L842 + 非静态初始化器令人困惑 + 建议: 将初始化逻辑移到构造函数或工厂方法中。 +- 🟡 `pmd:AtLeastOneConstructor` L848 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L849 + Missing commented default access modifier on field 's' +- 🟡 `pmd:CommentDefaultAccessModifier` L850 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:NullAssignment` L851 + 将对象赋值为 null 是代码坏味道 + 建议: 用 Optional 或空集合/空对象模式替代 null 赋值。 +- 🟡 `pmd:AtLeastOneConstructor` L856 + Each class should declare at least one constructor +- 🟡 `pmd:OverrideBothEqualsAndHashcode` L857 + 重写 equals() 时应同时重写 hashCode() + 建议: 为相等的对象保证 hashCode 一致,避免集合类行为异常。 +- 🟡 `pmd:MissingOverride` L857 + 重写方法缺少 @Override 注解 + 建议: 在继承或实现的方法上添加 @Override 注解。 +- 🟡 `pmd:AtLeastOneConstructor` L863 + Each class should declare at least one constructor +- 🟡 `pmd:MissingOverride` L864 + The method 'compareTo(CmpOnly)' is missing an @Override annotation. +- 🟡 `pmd:OverrideBothEqualsAndHashCodeOnComparable` L864 + 实现 Comparable 时应同时重写 equals() 和 hashCode() + 建议: 保持 compareTo、equals、hashCode 三者语义一致。 +- 🟡 `pmd:AtLeastOneConstructor` L870 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L871 + Missing commented default access modifier on field 'c' +- 🟡 `pmd:ReplaceJavaUtilCalendar` L871 + 应使用 java.time 替代 java.util.Calendar + 建议: 使用 LocalDate/LocalDateTime/ZonedDateTime 等新时间 API。 +- 🟡 `pmd:AtLeastOneConstructor` L875 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L876 + Missing commented default access modifier on field 'd' +- 🟡 `pmd:ReplaceJavaUtilDate` L876 + 应使用 java.time 替代 java.util.Date + 建议: 使用 Instant/LocalDateTime 并配合 DateTimeFormatter 处理格式。 +- 🟡 `pmd:ReplaceJavaUtilDate` L876 + Usage of java.util.Date should be replaced with classes from java.time +- 🟡 `pmd:AtLeastOneConstructor` L880 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L881 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:AtLeastOneConstructor` L887 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L888 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:OnlyOneReturn` L890 + A method should have only one exit point, and that should be the last statement in the method +- 🟡 `pmd:ReturnFromFinallyBlock` L892 + 避免在 finally 块中返回值 + 建议: 从 try/catch 中返回结果,finally 只做资源清理。 +- 🟡 `pmd:AtLeastOneConstructor` L898 + Each class should declare at least one constructor +- 🟡 `pmd:AvoidFieldNameMatchingTypeName` L899 + 字段名与类名相同容易混淆 + 建议: 重命名字段,例如 sdf 改为 dateFormat。 +- 🟡 `pmd:CommentDefaultAccessModifier` L899 + Missing commented default access modifier on field 'sdf' +- 🟡 `pmd:SimpleDateFormatNeedsLocale` L899 + SimpleDateFormat 实例化时应指定 Locale + 建议: new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT)。 +- 🟡 `pmd:AtLeastOneConstructor` L903 + Each class should declare at least one constructor +- 🟡 `pmd:AvoidStringBufferField` L904 + StringBuffer 字段可能造成内存问题 + 建议: 优先使用 StringBuilder,并避免在长生命周期对象中持有大缓冲区。 +- 🟡 `pmd:CommentDefaultAccessModifier` L904 + Missing commented default access modifier on field 'sb' +- 🟡 `pmd:AtLeastOneConstructor` L908 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L909 + Missing commented default access modifier on method 'equals(String)' +- 🟡 `pmd:AtLeastOneConstructor` L914 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L915 + Missing commented default access modifier on method 'hashcode()' +- 🟡 `pmd:AtLeastOneConstructor` L920 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L921 + Missing commented default access modifier on field 's' +- 🟡 `pmd:AtLeastOneConstructor` L925 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L926 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:UnconditionalIfStatement` L927 + 不要使用恒真/恒假的 if 语句 + 建议: 删除无条件 if,直接执行其中的代码或删除整个语句块。 +- 🟡 `pmd:AtLeastOneConstructor` L934 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L935 + Missing commented default access modifier on method 'bad(String)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L935 + Parameter 's' is not assigned and could be declared final +- 🟡 `pmd:EmptyControlStatement` L936 + Empty if statement +- 🟡 `pmd:AtLeastOneConstructor` L942 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L943 + Missing commented default access modifier on method 'bad(int)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L943 + Parameter 'x' is not assigned and could be declared final +- 🟡 `pmd:UnusedLocalVariable` L944 + Avoid unused local variables such as 's'. +- 🟡 `pmd:UnnecessaryConversionTemporary` L944 + 避免不必要的临时转换对象 + 建议: 使用 String.valueOf(x) 替代 new Integer(x).toString()。 +- 🟡 `pmd:PrimitiveWrapperInstantiation` L944 + Do not use `new Integer(...)`, prefer `Integer.valueOf(...)` +- 🟡 `pmd:AtLeastOneConstructor` L949 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L950 + Missing commented default access modifier on field 's' +- 🟡 `pmd:OverrideBothEqualsAndHashcode` L951 + Ensure you override both equals() and hashCode() +- 🟡 `pmd:MissingOverride` L951 + The method 'equals(Object)' is missing an @Override annotation. +- 🟡 `pmd:MethodArgumentCouldBeFinal` L951 + Parameter 'o' is not assigned and could be declared final +- 🟡 `pmd:EmptyControlStatement` L952 + Empty if statement +- 🟡 `pmd:AtLeastOneConstructor` L959 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L960 + Missing commented default access modifier on method 'bad(String, String)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L960 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:MethodArgumentCouldBeFinal` L960 + Parameter 'b' is not assigned and could be declared final +- 🟡 `pmd:CompareObjectsWithEquals` L961 + Use equals() to compare object references. +- 🟡 `pmd:UseEqualsToCompareStrings` L961 + Use equals() to compare strings instead of '==' or '!=' +- 🟡 `pmd:AtLeastOneConstructor` L966 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L967 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:UselessPureMethodCall` L968 + Do not call pure method length if the result is not used. +- 🟡 `pmd:AtLeastOneConstructor` L973 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L974 + Missing commented default access modifier on method 'bad(String)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L974 + Parameter 's' is not assigned and could be declared final +- 🟡 `pmd:UselessPureMethodCall` L975 + Do not call pure method toUpperCase if the result is not used. +- 🟡 `pmd:UseLocaleWithCaseConversions` L975 + toUpperCase()/toLowerCase() 应指定 Locale + 建议: 使用 s.toUpperCase(Locale.ROOT) 或指定业务 locale。 +- 🟡 `pmd:AtLeastOneConstructor` L980 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L981 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:UnusedLocalVariable` L982 + Avoid unused local variables such as 'cl'. +- 🟡 `pmd:UseProperClassLoader` L982 + getClassLoader() 在 J2EE 中可能不符合预期 + 建议: 使用 Thread.currentThread().getContextClassLoader()。 +- 🟡 `pmd:AtLeastOneConstructor` L987 + Each class should declare at least one constructor +- 🟡 `pmd:AvoidFieldNameMatchingMethodName` L988 + 字段名与同名方法容易混淆 + 建议: 重命名字段或方法,避免同名歧义。 +- 🟡 `pmd:CommentDefaultAccessModifier` L988 + Missing commented default access modifier on field 'value' +- 🟡 `pmd:CommentDefaultAccessModifier` L990 + Missing commented default access modifier on method 'value()' +- 🟡 `pmd:AtLeastOneConstructor` L995 + Each class should declare at least one constructor +- 🟡 `pmd:AvoidFieldNameMatchingTypeName` L996 + It is somewhat confusing to have a field name matching the declaring class name +- 🟡 `pmd:CommentDefaultAccessModifier` L996 + Missing commented default access modifier on field 'TypeName' +- 🟡 `pmd:AtLeastOneConstructor` L1000 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1001 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:AvoidCatchingGenericException` L1004 + Avoid catching Exception in try-catch block +- 🟡 `pmd:EmptyControlStatement` L1005 + Empty if statement +- 🟡 `pmd:AvoidInstanceofChecksInCatchClause` L1005 + catch 块中不应使用 instanceof 判断异常类型 + 建议: 为每种异常类型增加独立的 catch 子句。 +- 🟡 `pmd:CommentDefaultAccessModifier` L1009 + Missing commented default access modifier on method 'doWork()' +- 🟡 `pmd:AtLeastOneConstructor` L1014 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1015 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L1016 + Local variable 'x' could be declared final +- 🟡 `pmd:TooFewBranchesForSwitch` L1017 + switch 分支少于三个,使用 if 更高效 + 建议: 将 switch 改为 if/else if 判断。 +- 🟡 `pmd:NonExhaustiveSwitch` L1017 + switch 不完整,应包含 default 或所有枚举分支 + 建议: 补充 default 分支处理未知情况。 +- 🟡 `pmd:NonCaseLabelInSwitch` L1020 + switch 中出现了非 case 标签 + 建议: 移除标签,或重构 switch 逻辑。 +- 🟡 `pmd:UnusedLabel` L1020 + 存在未使用的标签 + 建议: 删除未引用标签,避免误导。 +- 🟡 `pmd:PublicMemberInNonPublicType` L1035 + Public member 'getInstance' declared in a non-public type +- 🟡 `pmd:PublicMemberInNonPublicType` L1039 + Public member 'getInstance' declared in a non-public type +- 🟡 `pmd:MethodArgumentCouldBeFinal` L1039 + Parameter 'obj' is not assigned and could be declared final +- 🟡 `pmd:VariableCanBeInlined` L1040 + 局部变量可以内联,不需要额外存储 + 建议: 直接返回值或表达式,减少中间变量。 +- 🟡 `pmd:LocalVariableCouldBeFinal` L1040 + Local variable 's' could be declared final +- 🟡 `pmd:SignatureDeclareThrowsException` L1047 + A method/constructor should not explicitly throw java.lang.Exception +- 🟡 `pmd:UnsupportedJdkApiUsage` L1048 + 使用了不受支持的 JDK API(如 sun.misc.Unsafe) + 建议: 改用标准 JDK API,例如 VarHandle/Atomic 类或通过受支持方式获取 Unsafe。 +- 🟡 `pmd:AtLeastOneConstructor` L1053 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1054 + Missing commented default access modifier on method 'bar()' +- 🟡 `pmd:IdempotentOperations` L1056 + 存在幂等操作(如变量赋值给自身/重复转换) + 建议: 删除重复或自我赋值,保留一次有效操作。 +- 🟡 `pmd:UnusedAssignment` L1056 + The value assigned to variable 'x' is never used +- 🟡 `pmd:AtLeastOneConstructor` L1061 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L1062 + Public member 'hashcode' declared in a non-public type +- 🟡 `pmd:SuspiciousHashcodeMethodName` L1062 + 方法名与 hashCode() 高度相似,但签名不符 + 建议: 重命名为 hashcode -> hashCode,并返回 int 且加上 @Override。 +- 🟡 `pmd:AtLeastOneConstructor` L1068 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1069 + Missing commented default access modifier on method 'foo()' +- 🟡 `pmd:SuspiciousOctalEscape` L1070 + 字符串中的八进制转义后紧跟数字字符很可疑 + 建议: 将转义拆分或改用 Unicode 转义,避免歧义。 +- 🟡 `pmd:AtLeastOneConstructor` L1075 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1076 + Missing commented default access modifier on method 'bad(String)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L1076 + Parameter 'buz' is not assigned and could be declared final +- 🟡 `pmd:LocalVariableCouldBeFinal` L1077 + Local variable 'answer' could be declared final +- 🟡 `pmd:LiteralsFirstInComparisons` L1077 + 字符串比较时应将字面量放在前面 + 建议: 使用 "BAZ".equals(buz) 避免 NPE。 +- 🟡 `pmd:UnnecessaryCaseChange` L1077 + 使用 toUpperCase/toLowerCase().equals() 不如 equalsIgnoreCase 清晰 + 建议: 改为 s1.equalsIgnoreCase(s2)。 +- 🟡 `pmd:UseLocaleWithCaseConversions` L1077 + When doing a String.toLowerCase()/toUpperCase() call, use a Locale +- 🟡 `pmd:AtLeastOneConstructor` L1083 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L1084 + Public member 'method1' declared in a non-public type +- 🟡 `pmd:PublicMemberInNonPublicType` L1087 + Public member 'method' declared in a non-public type +- 🟡 `pmd:MethodArgumentCouldBeFinal` L1087 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:UnusedNullCheckInEquals` L1088 + equals() 中的 null 检查未被使用或位置不当 + 建议: 直接调用非空对象.equals(),或先用 Objects.equals() 统一判空。 +- 🟡 `pmd:AtLeastOneConstructor` L1095 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1097 + Missing commented default access modifier on method 'bar()' +- 🟡 `pmd:AvoidCatchingGenericException` L1100 + Avoid catching Exception in try-catch block +- 🟡 `pmd:CommentDefaultAccessModifier` L1104 + Missing commented default access modifier on method 'doWork()' +- 🟡 `pmd:AtLeastOneConstructor` L1109 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1111 + Missing commented default access modifier on method 'bar()' +- 🟡 `pmd:AtLeastOneConstructor` L1118 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1119 + Missing commented default access modifier on method 'bar()' +- 🟡 `pmd:AvoidDuplicateLiterals` L1120 + 字符串字面量重复出现多次 + 建议: 提取为常量,避免重复字符串字面量。 +- 🟡 `pmd:CommentDefaultAccessModifier` L1125 + Missing commented default access modifier on method 'buz(String)' +- 🟡 `pmd:AtLeastOneConstructor` L1130 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1131 + Missing commented default access modifier on method 'foo()' +- 🟡 `pmd:JumbledIncrementer` L1133 + 内层循环修改了外层循环的递增变量,循环逻辑混乱 + 建议: 确保内层循环更新自己的控制变量,不要更新外层循环变量。 +- 🟡 `pmd:LocalVariableCouldBeFinal` L1133 + Local variable 'k' could be declared final +- 🟡 `pmd:AvoidReassigningLoopVariables` L1133 + Avoid reassigning the loop control variable 'i' +- 🟡 `pmd:AtLeastOneConstructor` L1141 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1142 + Missing commented default access modifier on method 'foo()' +- 🟡 `pmd:AvoidLiteralsInIfCondition` L1144 + Avoid using literals such as 5 in if statements +- 🟡 `pmd:AtLeastOneConstructor` L1152 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1153 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L1154 + Local variable 'numbers' could be declared final +- 🟡 `pmd:CollectionTypeMismatch` L1155 + 集合操作使用了与泛型类型不匹配的对象 + 建议: 确保存入/取出/删除的元素类型与泛型一致,例如用 Integer 而不是 String。 +- 🟡 `pmd:UseConcurrentHashMap` L1156 + 并发访问场景应使用 ConcurrentHashMap + 建议: 将 HashMap 改为 ConcurrentHashMap,或同步访问。 +- 🟡 `pmd:LocalVariableCouldBeFinal` L1156 + Local variable 'map' could be declared final +- 🟡 `pmd:UselessPureMethodCall` L1157 + Do not call pure method get if the result is not used. +- 🟡 `pmd:CollectionTypeMismatch` L1157 + Object of type 'int' cannot be in collection expecting 'java.lang.String' +- 🟡 `pmd:LocalVariableCouldBeFinal` L1158 + Local variable 'names' could be declared final +- 🟡 `pmd:UselessPureMethodCall` L1159 + Do not call pure method contains if the result is not used. +- 🟡 `pmd:CollectionTypeMismatch` L1159 + Object of type 'int' cannot be in collection expecting 'java.lang.String' +- 🟡 `pmd:AtLeastOneConstructor` L1164 + Each class should declare at least one constructor +- 🟡 `pmd:AtLeastOneConstructor` L1165 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1165 + Missing commented default access modifier on nested class 'C' +- 🟡 `pmd:CommentDefaultAccessModifier` L1166 + Missing commented default access modifier on method 'varargs(Object[])' +- 🟡 `pmd:CommentDefaultAccessModifier` L1167 + Missing commented default access modifier on method 'call()' +- 🟡 `pmd:ConfusingArgumentToVarargsMethod` L1168 + 可变参数调用意图不清晰 + 建议: 显式转换为 Object 或 Object[],或直接展开参数,避免歧义。 +- 🟡 `pmd:ConfusingArgumentToVarargsMethod` L1169 + Unclear if a varargs or non-varargs call is intended. Cast to Object or Object[] to clarify intent. +- 🟡 `pmd:AtLeastOneConstructor` L1175 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1176 + Missing commented default access modifier on method 'bar(Object, String)' +- 🟡 `pmd:MethodArgumentCouldBeFinal` L1176 + Parameter 'a' is not assigned and could be declared final +- 🟡 `pmd:MethodArgumentCouldBeFinal` L1176 + Parameter 'baz' is not assigned and could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L1184 + Each class should declare at least one constructor +- 🟡 `pmd:UnusedPrivateField` L1186 + Avoid unused private fields such as 'stream'. +- 🟡 `pmd:NonSerializableClass` L1186 + 可序列化类包含不可序列化的字段 + 建议: 将该字段标记为 transient,或改为可序列化类型。 +- 🟡 `pmd:AtLeastOneConstructor` L1190 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1191 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:CommentDefaultAccessModifier` L1198 + Missing commented default access modifier on method 'doWork()' +- 🟡 `pmd:AtLeastOneConstructor` L1204 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1205 + Missing commented default access modifier on method 'bad()' +- 🟡 `pmd:AtLeastOneConstructor` L1215 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1216 + Missing commented default access modifier on method 'foo()' +- 🟡 `pmd:AvoidLiteralsInIfCondition` L1219 + Avoid using literals such as 25 in if statements +- 🟡 `pmd:AtLeastOneConstructor` L1228 + Each class should declare at least one constructor +- 🟡 `pmd:CommentDefaultAccessModifier` L1229 + Missing commented default access modifier on method 'foo()' +- 🟡 `pmd:LocalVariableCouldBeFinal` L1230 + Local variable 'i' could be declared final +- 🟡 `pmd:LocalVariableCouldBeFinal` L1231 + Local variable 'b' could be declared final +- 🟡 `pmd:AtLeastOneConstructor` L1237 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L1238 + Public member 'bar' declared in a non-public type +- 🟡 `pmd:MethodArgumentCouldBeFinal` L1238 + Parameter 'string' is not assigned and could be declared final +- 🟡 `pmd:LiteralsFirstInComparisons` L1239 + Position literals first in String comparisons +- 🟡 `pmd:OnlyOneReturn` L1240 + A method should have only one exit point, and that should be the last statement in the method +- 🟡 `pmd:LiteralsFirstInComparisons` L1242 + Position literals first in String comparisons +- 🟡 `pmd:OnlyOneReturn` L1243 + A method should have only one exit point, and that should be the last statement in the method +- 🟡 `pmd:AtLeastOneConstructor` L1252 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L1254 + Public member 'clone' declared in a non-public type +- 🟡 `pmd:CloneMethodReturnTypeMustMatchClassName` L1254 + clone() 返回类型必须与类名一致 + 建议: 将 clone() 返回类型改为当前类名。 +- 🟡 `pmd:CloneMethodMustImplementCloneable` L1254 + 只有实现 Cloneable 接口才应实现 clone() 方法 + 建议: 要么移除 clone() 方法,要么让类实现 Cloneable。 +- 🟡 `pmd:AtLeastOneConstructor` L1260 + Each class should declare at least one constructor +- 🟡 `pmd:CloneMethodReturnTypeMustMatchClassName` L1262 + The return type of the clone() method must be the class name when implements Cloneable +- 🟡 `pmd:CloneMethodMustBePublic` L1262 + 实现 Cloneable 时 clone() 方法必须为 public + 建议: 将 protected clone() 改为 public CloneableType clone()。 +- 🟡 `pmd:OnlyOneReturn` L1264 + A method should have only one exit point, and that should be the last statement in the method +- 🟡 `pmd:AtLeastOneConstructor` L1272 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L1274 + Public member 'clone' declared in a non-public type +- 🟡 `pmd:CloneMethodReturnTypeMustMatchClassName` L1274 + The return type of the clone() method must be the class name when implements Cloneable +- 🟡 `pmd:OnlyOneReturn` L1276 + A method should have only one exit point, and that should be the last statement in the method +- 🟡 `pmd:AtLeastOneConstructor` L1284 + Each class should declare at least one constructor +- 🟡 `pmd:PublicMemberInNonPublicType` L1286 + Public member 'clone' declared in a non-public type +- 🟡 `pmd:CloneMethodReturnTypeMustMatchClassName` L1286 + The return type of the clone() method must be the class name when implements Cloneable +- 🟡 `pmd:AtLeastOneConstructor` L1294 + Each class should declare at least one constructor +- 🟡 `pmd:EmptyFinalizer` L1296 + finalize() 方法为空,没有实际作用 + 建议: 删除空 finalize 方法,或使用 Cleaner 清理资源。 +- 🟡 `pmd:AtLeastOneConstructor` L1301 + Each class should declare at least one constructor +- 🟡 `pmd:FinalizeDoesNotCallSuperFinalize` L1304 + finalize() 方法应最后调用 super.finalize() + 建议: 在 finalize() 末尾添加 super.finalize()。 +- 🟡 `pmd:CommentDefaultAccessModifier` L1306 + Missing commented default access modifier on method 'cleanup()' +- 🟡 `pmd:AtLeastOneConstructor` L1311 + Each class should declare at least one constructor +- 🟡 `pmd:FinalizeOnlyCallsSuperFinalize` L1313 + finalize() 只调用 super.finalize(),没有实际清理逻辑 + 建议: 删除无意义的 finalize,或在其中加入真正的资源清理逻辑。 +- 🟡 `pmd:AtLeastOneConstructor` L1319 + Each class should declare at least one constructor +- 🟡 `pmd:FinalizeOnlyCallsSuperFinalize` L1320 + Finalize should do something besides just calling super.finalize() +- 🟡 `pmd:MissingOverride` L1320 + The method 'finalize()' is missing an @Override annotation. +- 🟡 `pmd:FinalizeOverloaded` L1323 + finalize 方法不应被重载 + 建议: 删除重载的 finalize(int) 方法。 +- 🟡 `pmd:AtLeastOneConstructor` L1328 + Each class should declare at least one constructor +- 🟡 `pmd:FinalizeOnlyCallsSuperFinalize` L1330 + Finalize should do something besides just calling super.finalize() +- 🟡 `pmd:FinalizeShouldBeProtected` L1330 + finalize() 应声明为 protected + 建议: 将 public finalize() 改为 protected finalize()。 +- 🟡 `pmd:PublicMemberInNonPublicType` L1330 + Public member 'finalize' declared in a non-public type +- 🟡 `pmd:AtLeastOneConstructor` L1338 + Each class should declare at least one constructor +- 🟡 `pmd:ProperLogger` L1339 + logger 应定义为 private static final,并持有正确的类 + 建议: 改为 private static final Logger LOG = LoggerFactory.getLogger(Class.class); +- 🟡 `pmd:AtLeastOneConstructor` L1343 + Each class should declare at least one constructor +- 🟡 `pmd:ProperLogger` L1344 + Logger should be defined private static final and have the correct class +- 🟡 `pmd:CommentDefaultAccessModifier` L1345 + Missing commented default access modifier on method 'bar()' +- 🟡 `pmd:AvoidCatchingGenericException` L1348 + Avoid catching Exception in try-catch block +- 🟡 `pmd:CommentDefaultAccessModifier` L1352 + Missing commented default access modifier on method 'doWork()' +- 🟡 `pmd:MissingSerialVersionUID` L1359 + Classes implementing Serializable should set a serialVersionUID +- 🟡 `pmd:AtLeastOneConstructor` L1359 + Each class should declare at least one constructor +- 🟡 `pmd:UnusedPrivateField` L1360 + Avoid unused private fields such as 'value'. +- 🟡 `pmd:AtLeastOneConstructor` L1364 + Each class should declare at least one constructor +- 🟡 `pmd:UnusedPrivateField` L1366 + Avoid unused private fields such as 'nonSerializableField'. +- 🟡 `pmd:ImmutableField` L1366 + Field 'nonSerializableField' may be declared final +- 🟡 `pmd:PublicMemberInNonPublicType` L1378 + Public member 'getInstance' declared in a non-public type +- 🟡 `pmd:PublicMemberInNonPublicType` L1390 + Public member 'getInstance' declared in a non-public type +- 🟡 `pmd:NonThreadSafeSingleton` L1391 + 单例实现不是线程安全的 + 建议: 使用 enum 单例、静态持有者(holder)或双重检查加 volatile。 +- 🔵 `pmd:UnnecessaryFullyQualifiedName` L402 + 不必要使用全限定名 + 建议: 使用已导入的简单类名代替全限定名。 +- 🔵 `pmd:DoNotThrowExceptionInFinally` L727 + 在 finally 块中抛出异常会使控制流难以理解 + 建议: 不要在 finally 中抛出异常,先记录或吞掉 finally 中的异常。 +- 🔵 `pmd:InstantiationToGetClass` L801 + 不要仅为获取 Class 对象而实例化 + 建议: 使用 Integer.class 而不是 new Integer(1).getClass()。 +- 🔵 `pmd:StringBufferInstantiationWithChar` L904 + new StringBuffer(char) 会把 char 隐式转为 int 容量 + 建议: 使用 new StringBuffer() 或 new StringBuffer("c") 明确意图。 +- 🔵 `pmd:InvalidLogMessageFormat` L1112 + 日志消息格式参数数量不匹配 + 建议: 修正占位符数量:一个 {} 对应一个参数。 +- 🔵 `pmd:InvalidLogMessageFormat` L1113 + Too many arguments, expected 1 argument but found 2 +- 🔵 `pmd:UnnecessaryFullyQualifiedName` L1184 + Unnecessary qualifier 'java.io': 'Serializable' is already in scope because it is imported in this file + +AI 审查 · 9 条建议 + +- 🔴 [AI] [bug] `rethrow-missing-throws` L48 + **捕获 IOException 后重新抛出但方法未声明 throws IOException,编译失败** + ReThrow.bad() 中 catch (IOException e) 后直接 throw e,但 bad() 没有 throws IOException,无法编译。 + 建议: 在方法签名上增加 throws IOException,或者更简单:不要捕获该异常,直接让 doWork() 的异常向外传播。 +- 🔴 [AI] [bug] `wrap-same-missing-throws` L61 + **包装 IOException 抛出但方法未声明 throws IOException,编译失败** + WrapSame.bad() 中 catch 后 throw new IOException(...),但 bad() 未声明 throws IOException,代码无法编译。 + 建议: 为 bad() 增加 throws IOException,或捕获后改为抛出一个非受检异常。 +- 🔴 [AI] [bug] `finalize-protected-inaccessible` L565 + **显式调用 Object.finalize() 违反访问控制,无法编译** + CallFinalize.bad() 中通过 Object 引用调用 o.finalize(),但 Object.finalize() 是 protected 方法,不在同包且不是通过子类引用访问,编译不通过。 + 建议: 删除该调用;如果需要清理资源,使用 AutoCloseable/Cleaner。 +- 🔴 [AI] [bug] `null-inputstream-skip-npe` L637 + **InputStream 初始化为 null 后直接调用 skip(),必现 NPE** + CheckSkip.bad() 中 InputStream in = null,随后调用 in.skip(10),运行时必然抛出 NullPointerException。 + 建议: 初始化真实流,并用 try-with-resources 管理生命周期,同时检查 skip 返回值。 +- 🔴 [AI] [performance] `infinite-loop-inner-increment` L1133 + **内层循环误递增外层变量 i,且 k 永不变,导致无限循环** + JumbledInc.foo() 的内层循环 for (int k = 0; k < 20; i++) 更新的是 i 而不是 k,k 恒为 0,内层循环永不退出,程序将挂起。 + 建议: 内层循环应递增自己的控制变量 k。 +- 🟡 [AI] [design] `bean-getter-setter-naming` L317 + **getter/setter 未遵循 JavaBean 命名规范,影响框架绑定** + BadBean 中 getname/setname 不符合 JavaBean 规范,应为 getName/setName,否则很多序列化/绑定框架无法识别。 + 建议: 将 getter 改为 getName(),setter 改为 setName(String name)。 +- 🟡 [AI] [security] `singleton-cast-classcastexception` L1039 + **重载 getInstance(Object) 中无类型检查直接强转,会抛 ClassCastException** + SingletonDemo.getInstance(Object obj) 直接 (SingletonDemo) obj,传入非 SingletonDemo 对象时抛出 ClassCastException,且该重载破坏了单例语义。 + 建议: 删除该重载方法;如果确需接收对象,应先 instanceof 校验后再处理。 +- 🟡 [AI] [bug] `log-exception-as-string` L1101 + **日志只输出异常的 toString,丢失堆栈信息** + CorrectLog.bar() 中 _LOG.error(String.valueOf(e)) 只记录异常字符串,无法看到堆栈;应把异常对象作为最后一个参数传给日志 API。 + 建议: 使用 _LOG.error("doWork failed", e),保留异常堆栈。 +- 🟡 [AI] [bug] `loop-break-on-first-iteration` L1222 + **循环第一次迭代就 break,后续逻辑成为死代码** + BranchLastInLoop.foo() 中 if (i > 25) 永远不成立(i 最大为 9),而循环体末尾的 break 无条件执行,导致循环只执行一次。 + 建议: 检查循环终止条件,删除多余的 break,或把 break 放入有意义的条件判断中。 diff --git a/data/demo-pmd/reports/EJBNamingDemo-review.md b/data/demo-pmd/reports/EJBNamingDemo-review.md new file mode 100644 index 0000000..2c6f373 --- /dev/null +++ b/data/demo-pmd/reports/EJBNamingDemo-review.md @@ -0,0 +1,52 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\codestyle\extra\EJBNamingDemo.java` +**语言:** java +**耗时:** 213.0s +**分析工具:** pmd + +--- + +总计: 11 | 错误: 3 | 警告: 2 | 建议: 6 + +静态分析 · 8 个问题 + +- 🔴 `pmd:SystemPrintln` L35 + 第 35 行:使用了 System.out/err 输出。 + 建议: 避免直接使用 System.out.println,改用日志框架;例如使用 java.util.logging.Logger。 +- 🟡 `pmd:AtLeastOneConstructor` L22 + 第 22 行:每个类应至少声明一个构造器。 + 建议: 为 MissingBeanSuffix 添加 public 无参构造器(如 public MissingBeanSuffix() {}),不要依赖编译器生成的默认构造器。 +- 🔵 `pmd:UnnecessaryImport` L11 + 第 11 行:重复导入 'javax.ejb.EJBObject'。 + 建议: 删除第 11 行重复的 import javax.ejb.EJBObject,只保留第 8 行的一次导入。 +- 🔵 `pmd:LocalHomeNamingConvention` L14 + 第 14 行:会话 EJB 的本地 Home 接口应以 LocalHome 作为后缀。 + 建议: 将接口名从 MissingLocalHomeSuffixBean 改为 MissingLocalHomeSuffixLocalHome,使其以 LocalHome 结尾。 +- 🔵 `pmd:LocalInterfaceSessionNamingConvention` L18 + 第 18 行:会话 EJB 的本地接口应以 Local 作为后缀。 + 建议: 将接口名从 MissingLocalSuffixBean 改为 MissingLocalSuffixLocal,使其以 Local 结尾。 +- 🔵 `pmd:MDBAndSessionBeanNamingConvention` L22 + 第 22 行:SessionBean/MessageBean 实现类应以 Bean 作为后缀。 + 建议: 将类名从 MissingBeanSuffix 改为 MissingSuffixBean,使其以 Bean 结尾。 +- 🔵 `pmd:RemoteInterfaceNamingConvention` L26 + 第 26 行:会话 EJB 的远程接口不应带有后缀。 + 建议: 将接口名从 BadSuffixSession 改为 BadSuffix,去掉 Session 后缀。 +- 🔵 `pmd:RemoteSessionInterfaceNamingConvention` L30 + 第 30 行:会话 EJB 的远程 Home 接口应以 Home 作为后缀。 + 建议: 将接口名从 MissingHomeSuffixEJB 改为 MissingHomeSuffixHome,使其以 Home 结尾。 + +AI 审查 · 3 条建议 + +- 🔴 [AI] [bug] `multiple-public-top-level-types` L14 + **一个源文件中存在多个 public 顶层类型** + 第 14、18、22、26、30 行都声明了 public 顶层接口/类。Java 规定每个编译单元只能有一个 public 顶层类型,且源文件名必须与该 public 类型名一致,否则编译失败。 + 建议: 将每个 public 类型拆分为独立的 .java 文件(文件名与类型名一致);若这些类型不需要外部访问,可将除一个之外的 public 改为包私有。 +- 🔴 [AI] [bug] `session-bean-methods-not-implemented` L22 + **SessionBean 实现类缺少必需的方法** + MissingBeanSuffix 是具体类,实现了 javax.ejb.SessionBean,但没有实现接口要求的方法(ejbActivate、ejbPassivate、ejbRemove、setSessionContext),导致编译失败。 + 建议: 补全这四个方法的空实现。由于 EJB Bean 类不能是 abstract,不能通过改为抽象类来绕过。 +- 🟡 [AI] [design] `deprecated-ejb-2-api` L22 + **使用了已废弃的 EJB 2.x SessionBean API** + MissingBeanSuffix 实现的是 javax.ejb.SessionBean,这是 EJB 2.x 时代的接口;同时 Home/Object 接口也是 EJB 2.x 模式,这类 API 在现代 EJB 容器中已过时。 + 建议: 如有条件,迁移到 EJB 3.x:在 Bean 类上使用 @Stateless/@Stateful 注解,并通过 @Local/@Remote 注解暴露业务接口,避免实现大量回调方法和手工维护 Home/Component 接口。 diff --git a/data/demo-pmd/reports/FileItemDemo-review.md b/data/demo-pmd/reports/FileItemDemo-review.md new file mode 100644 index 0000000..e845596 --- /dev/null +++ b/data/demo-pmd/reports/FileItemDemo-review.md @@ -0,0 +1,68 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\performance\extra\FileItemDemo.java` +**语言:** java +**耗时:** 170.1s +**分析工具:** pmd + +--- + +总计: 16 | 错误: 3 | 警告: 12 | 建议: 1 + +静态分析 · 12 个问题 + +- 🔴 `pmd:SystemPrintln` L14 + L14:使用了 System.out/err 输出。 + 建议: 使用 java.util.logging 或 SLF4J/Log4j2 输出,便于统一日志级别和格式。 +- 🔴 `pmd:SystemPrintln` L19 + L19:使用了 System.out/err 输出。 + 建议: 用日志记录器替换 System.out.println。 +- 🔴 `pmd:SystemPrintln` L25 + L25:使用了 System.out/err 输出。 + 建议: 在入口类中使用日志记录器输出,或确认该输出仅用于命令行演示且不会被生产使用。 +- 🟡 `pmd:AtLeastOneConstructor` L11 + L11:每个类应至少声明一个构造器。 + 建议: 为 UseIOStreamFileItem 添加显式默认构造器;如果不希望外部实例化,可将构造器声明为 private。 +- 🟡 `pmd:CommentDefaultAccessModifier` L12 + L12:方法 process(FileItem) 缺少默认访问修饰符的注释。 + 建议: 为包级私有方法添加 /* default */ 注释,或显式改为 public/private/protected,以明确访问意图。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L12 + L12:参数 item 未被重新赋值,可以声明为 final。 + 建议: 将方法签名中的 FileItem item 改为 final FileItem item,避免方法体内意外重新赋值。 +- 🟡 `pmd:LocalVariableCouldBeFinal` L13 + L13:局部变量 data 未被重新赋值,可以声明为 final。 + 建议: 将 byte[] data 改为 final byte[] data,表达只读引用的意图。 +- 🟡 `pmd:UseIOStreamsWithApacheCommonsFileItem` L13 + L13:应避免调用高内存占用的 FileItem.get() 或 FileItem.getString()。 + 建议: 如果只需要文件大小,使用 item.getSize();如果需要内容,使用 item.getInputStream() 配合 try-with-resources 流式读取,避免将整个文件载入内存。 +- 🟡 `pmd:CommentDefaultAccessModifier` L17 + L17:方法 processString(FileItem) 缺少默认访问修饰符的注释。 + 建议: 与 process 一致,添加 /* default */ 注释或使用显式访问修饰符。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L17 + L17:参数 item 未被重新赋值,可以声明为 final。 + 建议: 将方法签名中的 FileItem item 改为 final FileItem item。 +- 🟡 `pmd:LocalVariableCouldBeFinal` L18 + L18:局部变量 s 未被重新赋值,可以声明为 final。 + 建议: 将 String s 改为 final String s。 +- 🟡 `pmd:UseIOStreamsWithApacheCommonsFileItem` L18 + L18:应避免调用高内存占用的 FileItem.get() 或 FileItem.getString()。 + 建议: 改为读取输入流并显式指定 UTF-8 字符集,使用 try-with-resources 关闭输入流;避免 FileItem.getString() 使用默认字符集。 + +AI 审查 · 4 条建议 + +- 🟡 [AI] [performance] `use-getsize-for-length-only` L13 + **process() 只需要文件长度时却把整个文件读入内存** + process(FileItem) 中仅用 data.length 获取字节数,但 FileItem.get() 会一次把整个上传文件载入 byte[]。当文件很大时会造成不必要的内存占用,甚至导致 OOM。FileItem.getSize() 可以在不读取内容的情况下返回文件大小。 + 建议: 将 byte[] data = item.get() 改为 long size = item.getSize(),并把 data.length 改为 size。若后续需要内容,再使用 item.getInputStream() 配合 try-with-resources 流式读取。 +- 🟡 [AI] [security] `enforce-upload-size-limits` L13 + **未限制上传文件大小,存在内存耗尽风险** + 代码直接对 FileItem 调用 get()/getString() 将完整内容读入内存。若 FileItem 来自不受信任的 HTTP multipart 上传,攻击者可提交超大文件,导致 JVM 堆内存被耗尽。虽然静态分析建议改用 getInputStream(),但流式读取仍应配合上传大小上限。 + 建议: 在解析上传时配置 ServletFileUpload.setFileSizeMax()/setSizeMax(),或将 DiskFileItemFactory 的阈值调低使大文件写入临时文件;读取前检查 item.getSize()。 +- 🟡 [AI] [bug] `explicit-charset-for-fileitem-read` L18 + **FileItem.getString() 使用平台默认字符集,导致编码不一致** + FileItem.getString() 未指定字符集时会使用运行平台的默认字符集。开发环境与生产环境字符集不同(如本地 GBK、服务器 UTF-8)时,读取同一表单字段或文件内容会得到不同结果。应显式指定 UTF-8 或与业务约定的编码。 + 建议: 调用 item.getString(StandardCharsets.UTF_8.name());若按静态分析改为 getInputStream() 流式读取,也要使用显式字符集的 Reader,并在 try-with-resources 中关闭流。 +- 🔵 [AI] [design] `explicit-access-modifiers` L12 + **类及方法使用隐式包级私有访问权限** + UseIOStreamFileItem 的 process/processString 没有显式访问修饰符,默认为包级私有。当前代码中这两个方法未被类内部调用,也未声明为 private;如果实际需要外部访问,包级私有会限制可见性;如果仅是辅助方法,应缩小为 private。 + 建议: 若方法仅类内部使用,添加 private 修饰符;若需对外提供,请将 UseIOStreamFileItem 放入以类名命名的独立文件并声明 public,同时为方法添加 public。 diff --git a/data/demo-pmd/reports/GodClassDemo-review.md b/data/demo-pmd/reports/GodClassDemo-review.md new file mode 100644 index 0000000..7ac13b7 --- /dev/null +++ b/data/demo-pmd/reports/GodClassDemo-review.md @@ -0,0 +1,273 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\design\extra\GodClassDemo.java` +**语言:** java +**耗时:** 197.9s +**分析工具:** pmd + +--- + +总计: 84 | 错误: 3 | 警告: 78 | 建议: 3 + +静态分析 · 79 个问题 + +- 🔴 `pmd:AvoidReassigningParameters` L57 + L57: 避免对参数 'x' 重新赋值 + 建议: 在方法内使用局部变量保存 x 的初始值,并对局部变量进行递减操作,保持参数不变。 +- 🔴 `pmd:AvoidReassigningParameters` L78 + L78: 避免对参数 'x' 重新赋值 + 建议: 在方法内使用局部变量保存 x 的初始值,并对局部变量进行递减操作,保持参数不变。 +- 🔴 `pmd:SystemPrintln` L181 + L181: 使用了 System.out/err 输出 + 建议: 使用日志框架(如 java.util.logging、SLF4J、Log4j2)记录信息,便于日志管理与级别控制。 +- 🟡 `pmd:AtLeastOneConstructor` L9 + L9: 每个类应至少声明一个构造函数 + 建议: 为类添加构造函数;若无需初始化逻辑,可声明一个空的包可见构造函数。 +- 🟡 `pmd:DataClass` L9 + L9: 类 'ExternalData' 被怀疑是数据类(WOC=0.000%, NOPA=10, NOAM=0, WMC=0) + 建议: 将公共字段改为私有,并添加构造器与行为方法;或使用 Java record 作为不可变数据传输对象(Java 14+)。 +- 🟡 `pmd:PublicMemberInNonPublicType` L10 + L10: 非公共类型 'ExternalData' 中的公共成员 'a' 应降低可见性 + 建议: 将字段 a 改为 private,并对外提供必要的 getter/setter(如果确实需要访问)。 +- 🟡 `pmd:PublicMemberInNonPublicType` L10 + L10: 非公共类型 'ExternalData' 中的公共成员 'b' 应降低可见性 + 建议: 将字段 b 改为 private,并对外提供必要的 getter/setter(如果确实需要访问)。 +- 🟡 `pmd:PublicMemberInNonPublicType` L10 + L10: 非公共类型 'ExternalData' 中的公共成员 'c' 应降低可见性 + 建议: 将字段 c 改为 private,并对外提供必要的 getter/setter(如果确实需要访问)。 +- 🟡 `pmd:PublicMemberInNonPublicType` L10 + L10: 非公共类型 'ExternalData' 中的公共成员 'd' 应降低可见性 + 建议: 将字段 d 改为 private,并对外提供必要的 getter/setter(如果确实需要访问)。 +- 🟡 `pmd:PublicMemberInNonPublicType` L10 + L10: 非公共类型 'ExternalData' 中的公共成员 'e' 应降低可见性 + 建议: 将字段 e 改为 private,并对外提供必要的 getter/setter(如果确实需要访问)。 +- 🟡 `pmd:PublicMemberInNonPublicType` L10 + L10: 非公共类型 'ExternalData' 中的公共成员 'f' 应降低可见性 + 建议: 将字段 f 改为 private,并对外提供必要的 getter/setter(如果确实需要访问)。 +- 🟡 `pmd:PublicMemberInNonPublicType` L10 + L10: 非公共类型 'ExternalData' 中的公共成员 'g' 应降低可见性 + 建议: 将字段 g 改为 private,并对外提供必要的 getter/setter(如果确实需要访问)。 +- 🟡 `pmd:PublicMemberInNonPublicType` L10 + L10: 非公共类型 'ExternalData' 中的公共成员 'h' 应降低可见性 + 建议: 将字段 h 改为 private,并对外提供必要的 getter/setter(如果确实需要访问)。 +- 🟡 `pmd:PublicMemberInNonPublicType` L10 + L10: 非公共类型 'ExternalData' 中的公共成员 'i' 应降低可见性 + 建议: 将字段 i 改为 private,并对外提供必要的 getter/setter(如果确实需要访问)。 +- 🟡 `pmd:PublicMemberInNonPublicType` L10 + L10: 非公共类型 'ExternalData' 中的公共成员 'j' 应降低可见性 + 建议: 将字段 j 改为 private,并对外提供必要的 getter/setter(如果确实需要访问)。 +- 🟡 `pmd:AtLeastOneConstructor` L14 + L14: 每个类应至少声明一个构造函数 + 建议: 为 GodClassDemo 添加构造函数;若该类仅作为工具类,建议将构造函数设为 private 禁止实例化。 +- 🟡 `pmd:GodClass` L14 + L14: 疑似上帝类(WMC=89, ATFD=105, TCC=0.000%) + 建议: 按单一职责将 GodClassDemo 拆分为多个类,将规则方法分组到不同类,并提升方法内聚性、降低对外部数据类的直接访问。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L16 + L16: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L16 + L16: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L18 + L18: 避免在 if 语句中使用字面量(如 1) + 建议: 定义常量并替换:private static final int THRESHOLD_1 = 1; 条件改为 x > THRESHOLD_1。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L19 + L19: 避免在 if 语句中使用字面量(如 2) + 建议: 定义常量并替换:private static final int THRESHOLD_2 = 2; 条件改为 x > THRESHOLD_2。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L22 + L22: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L22 + L22: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L24 + L24: 避免在 if 语句中使用字面量(如 1) + 建议: 定义常量并替换:private static final int THRESHOLD_1 = 1; 条件改为 x > THRESHOLD_1。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L25 + L25: 避免在 if 语句中使用字面量(如 2) + 建议: 定义常量并替换:private static final int THRESHOLD_2 = 2; 条件改为 x > THRESHOLD_2。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L28 + L28: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L28 + L28: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L34 + L34: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L34 + L34: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L46 + L46: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L46 + L46: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L52 + L52: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L56 + L56: 避免在 if 语句中使用字面量(如 10) + 建议: 定义常量并替换:private static final int THRESHOLD_10 = 10; 条件改为 x > THRESHOLD_10。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L61 + L61: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L61 + L61: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L69 + L69: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L82 + L82: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L82 + L82: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L84 + L84: 避免在 if 语句中使用字面量(如 1) + 建议: 定义常量并替换:private static final int THRESHOLD_1 = 1; 条件改为 x > THRESHOLD_1。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L84 + L84: 避免在 if 语句中使用字面量(如 2) + 建议: 定义常量并替换:private static final int THRESHOLD_2 = 2; 条件改为 x > THRESHOLD_2。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L85 + L85: 避免在 if 语句中使用字面量(如 3) + 建议: 定义常量并替换:private static final int THRESHOLD_3 = 3; 条件改为 x > THRESHOLD_3。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L88 + L88: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L88 + L88: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L97 + L97: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L97 + L97: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L99 + L99: 避免在 if 语句中使用字面量(如 5) + 建议: 定义常量并替换:private static final int THRESHOLD_5 = 5; 条件改为 x > THRESHOLD_5。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L100 + L100: 避免在 if 语句中使用字面量(如 10) + 建议: 定义常量并替换:private static final int THRESHOLD_10 = 10; 条件改为 x > THRESHOLD_10。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L103 + L103: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L103 + L103: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:TooFewBranchesForSwitch` L106 + L106: 分支少于三个的 switch 效率较低,建议改用 if 语句 + 建议: 将 switch (i % 2) 改为 if-else:if (i % 2 == 0) { r += d.a; } else { r += d.b; } +- 🟡 `pmd:AvoidLiteralsInIfCondition` L111 + L111: 避免在 if 语句中使用字面量(如 5) + 建议: 定义常量并替换:private static final int THRESHOLD_5 = 5; 条件改为 x > THRESHOLD_5。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L114 + L114: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L114 + L114: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L116 + L116: 避免在 if 语句中使用字面量(如 1) + 建议: 定义常量并替换:private static final int THRESHOLD_1 = 1; 条件改为 x > THRESHOLD_1。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L117 + L117: 避免在 if 语句中使用字面量(如 2) + 建议: 定义常量并替换:private static final int THRESHOLD_2 = 2; 条件改为 x > THRESHOLD_2。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L120 + L120: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L120 + L120: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L122 + L122: 避免在 if 语句中使用字面量(如 1) + 建议: 定义常量并替换:private static final int THRESHOLD_1 = 1; 条件改为 x > THRESHOLD_1。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L123 + L123: 避免在 if 语句中使用字面量(如 2) + 建议: 定义常量并替换:private static final int THRESHOLD_2 = 2; 条件改为 x > THRESHOLD_2。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L126 + L126: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L126 + L126: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L128 + L128: 避免在 if 语句中使用字面量(如 1) + 建议: 定义常量并替换:private static final int THRESHOLD_1 = 1; 条件改为 x > THRESHOLD_1。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L129 + L129: 避免在 if 语句中使用字面量(如 2) + 建议: 定义常量并替换:private static final int THRESHOLD_2 = 2; 条件改为 x > THRESHOLD_2。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L132 + L132: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L132 + L132: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L135 + L135: 避免在 if 语句中使用字面量(如 10) + 建议: 定义常量并替换:private static final int THRESHOLD_10 = 10; 条件改为 i > THRESHOLD_10。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L135 + L135: 避免在 if 语句中使用字面量(如 20) + 建议: 定义常量并替换:private static final int THRESHOLD_20 = 20; 条件改为 i > THRESHOLD_20。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L140 + L140: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L140 + L140: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L142 + L142: 避免在 if 语句中使用字面量(如 1) + 建议: 定义常量并替换:private static final int THRESHOLD_1 = 1; 条件改为 x > THRESHOLD_1。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L142 + L142: 避免在 if 语句中使用字面量(如 2) + 建议: 定义常量并替换:private static final int THRESHOLD_2 = 2; 条件改为 x > THRESHOLD_2。 +- 🟡 `pmd:AvoidLiteralsInIfCondition` L143 + L143: 避免在 if 语句中使用字面量(如 3) + 建议: 定义常量并替换:private static final int THRESHOLD_3 = 3; 条件改为 x > THRESHOLD_3。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L146 + L146: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L146 + L146: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L152 + L152: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L152 + L152: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L168 + L168: 参数 'd' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final ExternalData d。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L168 + L168: 参数 'x' 未被赋值,可声明为 final + 建议: 将参数声明为 final:final int x。 +- 🔵 `pmd:OneDeclarationPerLine` L10 + L10: 每行只声明一个变量,以增强代码可读性 + 建议: 将同一行的多个变量声明拆分为多行,每行一个变量。 + +AI 审查 · 5 条建议 + +- 🟡 [AI] [bug] `potential-null-dereference` L16 + **ExternalData 参数未做空值校验** + 所有 rule* 方法直接使用参数 d 的字段,未校验 d 是否为 null。当外部传入 null 时,方法会立即抛出 NullPointerException。 + 建议: 在每个方法入口增加防御性判断,如 if (d == null) throw new IllegalArgumentException("d must not be null");或使用 Objects.requireNonNull(d) 统一校验。 +- 🟡 [AI] [bug] `unreachable-branch-in-if-else-if` L18 + **if-else if 条件顺序导致后续分支不可达** + rule1、rule2、rule9、rule11、rule13、rule14、rule15、rule16、rule17 等方法中的 if-else if 链按从小到大判断,例如 rule1 中 if (x>0) 已覆盖所有正数,其后的 else if (x>1) 与 else if (x>2) 永远无法执行。 + 建议: 调整判断顺序,将范围更大的条件放在前面,或改用区间判断(如 x > 0 && x <= 1)。请根据业务语义改为正确的分段逻辑。 +- 🟡 [AI] [bug] `tautological-condition` L31 + **条件表达式恒为真** + rule3(L31)与 rule18(L149)中的 if (x > 1 || x < 20) 对任意整数 x 均成立,导致其分支总被执行,原条件失去判断意义。 + 建议: 检查业务意图。如果希望同时满足两个条件,应改为 if (x > 1 && x < 20);如果确实无条件执行,应移除 if 直接执行。 +- 🔵 [AI] [design] `meaningless-method-names` L16 + **规则方法使用无意义的数字命名** + rule1 到 rule20 的方法名无法描述业务行为,难以维护和理解。数字命名还暗示这些方法可能由复制粘贴生成,代码重复度高。 + 建议: 根据业务语义重命名方法(如 calculateDiscount、applyTax 等),并提取重复逻辑为公共方法。 +- 🔵 [AI] [performance] `inefficient-nested-loop` L90 + **rule10 存在 O(n²) 复杂度且可能产生巨大循环** + rule10 使用双重 for 循环(L90-94),当 x 较大时会造成严重的性能问题;若 x 来自用户输入,可能形成拒绝服务攻击。 + 建议: 评估业务逻辑,避免将未受控的外部输入直接作为循环上限;考虑降低时间复杂度或增加上限校验。 diff --git a/data/demo-pmd/reports/InvalidBeanDemo-review.md b/data/demo-pmd/reports/InvalidBeanDemo-review.md new file mode 100644 index 0000000..9a15b91 --- /dev/null +++ b/data/demo-pmd/reports/InvalidBeanDemo-review.md @@ -0,0 +1,49 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\org\example\beans\InvalidBeanDemo.java` +**语言:** java +**耗时:** 106.9s +**分析工具:** pmd + +--- + +总计: 10 | 错误: 1 | 警告: 8 | 建议: 1 + +静态分析 · 7 个问题 + +- 🔴 `pmd:SystemPrintln` L30 + 使用了 System.out / System.err 输出。 + 建议: 请改用日志框架(如 java.util.logging.Logger、SLF4J)记录输出,以便控制日志级别、格式和输出目标。 +- 🟡 `pmd:AtLeastOneConstructor` L7 + 每个类都应该声明至少一个构造函数。 + 建议: 请为 MyBean 添加显式的无参构造器,例如 `public MyBean() {}`,以保证符合类的基本构造约定。 +- 🟡 `pmd:InvalidJavaBean` L8 + Bean 'MyBean' 的属性 'Label' 缺少 setter。 + 建议: 请为 label 属性添加标准 setter 方法:`public void setLabel(String label) { this.label = label; }`。 +- 🟡 `pmd:AtLeastOneConstructor` L16 + 每个类都应该声明至少一个构造函数。 + 建议: 请为 WrapException 添加包私有无参构造器,例如 `WrapException() {}`。 +- 🟡 `pmd:CommentDefaultAccessModifier` L17 + 方法 'bar()' 缺少注释掉的默认访问修饰符。 + 建议: 请在无修饰符方法前添加 `/* default */` 注释,以明确其包私有可见性,如:`/* default */ void bar() { ... }`。 +- 🟡 `pmd:AvoidThrowingNewInstanceOfSameException` L21 + 应避免在 catch 块中仅捕获异常,然后包装成同一类型的新异常并抛出。 + 建议: 请直接抛出原始异常,例如 `throw se;`,或者包装为具有更明确语义的其他异常类型。 +- 🟡 `pmd:CommentDefaultAccessModifier` L24 + 方法 'doWork()' 缺少注释掉的默认访问修饰符。 + 建议: 请在无修饰符方法前添加 `/* default */` 注释,如:`/* default */ void doWork() { ... }`。 + +AI 审查 · 3 条建议 + +- 🟡 [AI] [design] `bean-not-serializable` L7 + **JavaBean 未实现 Serializable** + MyBean 作为 JavaBean 未实现 java.io.Serializable,也未声明 serialVersionUID,在需要持久化或会话复制的场景中无法正常序列化。 + 建议: 为 MyBean 添加 `implements java.io.Serializable` 并声明 `private static final long serialVersionUID = 1L;`。同时建议补充无参构造器(静态分析已要求)和 setter。 +- 🟡 [AI] [bug] `unreachable-catch-block` L20 + **空方法调用后的 catch 块不可达** + doWork() 方法体为空,不会抛出任何异常,因此 bar() 中的 catch (IllegalStateException) 永远不会进入,属于死代码。异常处理流程在当前代码中无效。 + 建议: 若 doWork() 尚未实现,应删除 try-catch 并直接调用;若 doWork() 可能抛异常,应先补全方法体。建议去掉无意义的相同异常包装。 +- 🔵 [AI] [style] `one-top-level-class-per-file` L16 + **多个顶层类定义在同一个源文件中** + MyBean、WrapException、BeansMain 三个顶层类写在同一个 .java 文件中,使文件职责不单一,降低可读性和可维护性。 + 建议: 将 WrapException 和 BeansMain 分别抽取到独立源文件(WrapException.java、BeansMain.java),并为每个类保留必要的 public/包私有声明。 diff --git a/data/demo-pmd/reports/JUnit3RulesTest-review.md b/data/demo-pmd/reports/JUnit3RulesTest-review.md new file mode 100644 index 0000000..4f1d7bf --- /dev/null +++ b/data/demo-pmd/reports/JUnit3RulesTest-review.md @@ -0,0 +1,81 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\errorprone\extra\JUnit3RulesTest.java` +**语言:** java +**耗时:** 213.2s +**分析工具:** pmd + +--- + +总计: 20 | 错误: 4 | 警告: 14 | 建议: 2 + +静态分析 · 15 个问题 + +- 🔴 `pmd:MethodNamingConventions` L12 + 实例方法名 'TearDown' 不符合 '[a-z][a-zA-Z0-9]*' 命名规范(L12)。 + 建议: 将 TearDown() 重命名为 tearDown(),使其以大写字母开头变为小写开头,并作为 JUnit3 的清理方法使用。 +- 🔴 `pmd:SystemPrintln` L30 + 使用了 System.out/err(L30)。 + 建议: 在正式代码中改用日志框架,例如 java.util.logging.Logger;也可为 Junit3Main 注入输出流以便测试。 +- 🟡 `pmd:AtLeastOneConstructor` L9 + 每个类都应至少声明一个构造函数(L9)。 + 建议: 为 JUnitSpellingTest 添加显式构造函数,例如:public JUnitSpellingTest() { super(); }。若该类保留为 public 且供 JUnit3 使用,这个公共无参构造函数也满足 JUnit3 反射实例化的要求。 +- 🟡 `pmd:TestClassWithoutTestCases` L9 + 类 'JUnitSpellingTest' 可能是测试类,但未包含任何测试用例(L9)。 + 建议: 在该类中新增一个以 test 开头、返回 void、公共无参的测试方法,并添加断言。例如:public void testExample() { assertTrue(true); }。如果该类用于存放公共测试工具,则不应继承 TestCase。 +- 🟡 `pmd:JUnitSpelling` L10 + 你可能拼错了 JUnit 框架方法(setUp 或 tearDown)(L10)。 + 建议: 将 setup() 重命名为 setUp(),确保 JUnit3 将其识别为初始化方法。若方法体为空,请补充资源初始化逻辑;否则该声明无实际作用。 +- 🟡 `pmd:JUnitSpelling` L12 + 你可能拼错了 JUnit 框架方法(setUp 或 tearDown)(L12)。 + 建议: 将 TearDown() 重命名为 tearDown(),使其被 JUnit3 识别为 teardown 生命周期方法。 +- 🟡 `pmd:AtLeastOneConstructor` L17 + 每个类都应至少声明一个构造函数(L17)。 + 建议: 为 JUnitStaticSuiteTest 添加显式构造函数,例如:public JUnitStaticSuiteTest() { super(); }。注意测试类本身还应为 public,才能被 JUnit3 外部加载。 +- 🟡 `pmd:TestClassWithoutTestCases` L17 + 类 'JUnitStaticSuiteTest' 可能是测试类,但未包含任何测试用例(L17)。 + 建议: 将 suite() 改为 public static junit.framework.Test suite(),并返回包含测试方法的 TestSuite,例如:return new TestSuite(JUnitStaticSuiteTest.class)。同时确保类中至少有一个 test 开头的方法。 +- 🟡 `pmd:PublicMemberInNonPublicType` L18 + 在非 public 类型 JUnitStaticSuiteTest 中声明了 public 成员 'suite'(L18)。 + 建议: JUnit3 要求 suite() 为 public,因此最佳修复是将类 JUnitStaticSuiteTest 移到独立文件并声明为 public class JUnitStaticSuiteTest;不要简单地把方法改为包私有,否则 JUnit 无法调用 suite 入口。 +- 🟡 `pmd:JUnitStaticSuite` L18 + 你有一个 suite() 方法不是 public 且 static,JUnit 不会调用它来获取 TestSuite。这是你期望的吗?(L18) + 建议: 将方法签名改为 public static junit.framework.Test suite(),并返回一个 TestSuite 实例,例如 return new TestSuite(JUnitStaticSuiteTest.class)。 +- 🟡 `pmd:AtLeastOneConstructor` L23 + 每个类都应至少声明一个构造函数(L23)。 + 建议: 为 DetachedTest 添加显式构造函数,例如:public DetachedTest() { super(); }。同时建议将类改为 public 并放入独立文件。 +- 🟡 `pmd:DetachedTestCase` L24 + 可能存在脱离测试套件的 JUnit 测试用例(L24)。 + 建议: 确保测试类为 public,以便 JUnit3 反射实例化;并将该类纳入某个 TestSuite。若迁移到 JUnit4/5,请使用 @Test 注解替代 test 前缀。 +- 🟡 `pmd:PublicMemberInNonPublicType` L24 + 在非 public 类型 DetachedTest 中声明了 public 成员 'testSomething'(L24)。 + 建议: 将 DetachedTest 改为 public class,并放入独立文件 DetachedTest.java。JUnit3 测试方法必须为 public,因此不要降低方法的可见性。 +- 🟡 `pmd:UnitTestShouldIncludeAssert` L24 + 此单元测试应包含 assert() 或 fail()(L24)。 + 建议: 在 testSomething() 中添加有意义的断言,例如 assertEquals(2, 1 + 1)。空测试永远通过,无法保护代码。 +- 🟡 `pmd:UnitTestShouldUseTestAnnotation` L24 + 单元测试应使用 @Test 注解,否则不会运行。对于 JUnit Jupiter,还可使用 @RepeatedTest、@TestFactory、@TestTemplate 或 @ParameterizedTest 注解(L24)。 + 建议: 若迁移到 JUnit4/5,移除 TestCase 继承,在方法上添加 @Test,并使用 org.junit.jupiter.api.Assertions 断言。当前 JUnit3 风格可通过修正类可见性继续运行,但推荐升级。 + +AI 审查 · 5 条建议 + +- 🔴 [AI] [bug] `non-public-junit3-test-class` L17 + **JUnit3 测试类必须声明为 public 才能被发现** + JUnitStaticSuiteTest 和 DetachedTest 都是包私有类。JUnit3 运行器通过反射从外部包加载测试类,非 public 类会导致测试被跳过或抛出 IllegalAccessException。即使方法都声明为 public,类本身不可见也无法运行。 + 建议: 将两个测试类分别放入独立文件,并声明为 public class。移动后,默认的 public 无参构造即可满足 JUnit3 的基本实例化要求。 +- 🔴 [AI] [bug] `multiple-top-level-classes` L28 + **多个顶层类与 Java 文件结构冲突,main 入口不可用** + 本文件中的 JUnitSpellingTest 是 public 类,因此文件必须命名为 JUnitSpellingTest.java。Junit3Main 无法在同一文件中声明为 public,导致其 main 方法不能作为程序入口;同时 JUnitStaticSuiteTest 和 DetachedTest 不是 public,JUnit3 无法从外部包加载它们。这种多顶层类布局会造成测试被静默忽略、程序无法启动。 + 建议: 将 Junit3Main 移到独立文件并声明为 public class Junit3Main;将 JUnitStaticSuiteTest、DetachedTest 也分别移到独立文件并声明为 public class。如果使用 JUnit5,则无需继承 TestCase,文件结构更简单。 +- 🟡 [AI] [design] `empty-test-suite` L24 + **测试类没有真实断言,测试套件可能空转** + JUnitSpellingTest 没有任何 test 方法;JUnitStaticSuiteTest 只有无效的 suite() 且没有测试方法;DetachedTest.testSomething() 没有断言。这些测试即使全部通过也不能验证任何行为,容易让 CI 产生假阳性。 + 建议: 为每个测试类添加带断言的 test 方法;若某个类只是测试基类,则不应继承 TestCase。使用 JUnit5 的 @Test 和 Assertions 能更容易写出有效测试。 +- 🔵 [AI] [design] `legacy-junit3` L6 + **使用已停止维护的 JUnit3 测试框架** + 代码通过继承 junit.framework.TestCase 和 test 前缀编写测试,属于 JUnit3 风格。JUnit3 不支持现代测试特性(如异常断言、参数化测试、嵌套测试),不利于长期维护。 + 建议: 迁移到 JUnit4 或 JUnit5:移除 extends TestCase,测试方法加 @Test 注解,使用 org.junit.jupiter.api.Assertions 断言。迁移前至少先修复类可见性和空测试问题。 +- 🔵 [AI] [style] `abbreviation-in-name` L28 + **类名 Junit3Main 中 JUnit 缩写大小写不规范** + JUnit 是一个品牌名,通常缩写应保持全部大写。Junit3Main 看起来像类名大小写不规范,建议改为 JUnit3Main,并同步更新文件名和所有引用。 + 建议: 将 Junit3Main 重命名为 JUnit3Main,更新文件名为 JUnit3Main.java,并修改 main 方法中 Logger.getLogger(Junit3Main.class.getName()) 的类名引用。 diff --git a/data/demo-pmd/reports/JUnit4RulesTest-review.md b/data/demo-pmd/reports/JUnit4RulesTest-review.md new file mode 100644 index 0000000..589c85e --- /dev/null +++ b/data/demo-pmd/reports/JUnit4RulesTest-review.md @@ -0,0 +1,245 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\errorprone\extra\JUnit4RulesTest.java` +**语言:** java +**耗时:** 228.6s +**分析工具:** pmd + +--- + +总计: 74 | 错误: 12 | 警告: 62 | 建议: 0 + +静态分析 · 67 个问题 + +- 🔴 `pmd:WrongTestAnnotation` L11 + org.junit.Test 是 JUnit 4 的注解,而当前代码库正在使用 JUnit Jupiter。 + 建议: 将导入改为 org.junit.jupiter.api.Test(JUnit 5),并同步将 org.junit.Assert 迁移为 org.junit.jupiter.api.Assertions。 +- 🔴 `pmd:WrongTestAnnotation` L19 + org.junit.Test 是 JUnit 4 的注解,而当前代码库正在使用 JUnit Jupiter。 + 建议: 将导入改为 org.junit.jupiter.api.Test(JUnit 5),并同步将 org.junit.Assert 迁移为 org.junit.jupiter.api.Assertions。 +- 🔴 `pmd:WrongTestAnnotation` L25 + org.junit.Test 是 JUnit 4 的注解,而当前代码库正在使用 JUnit Jupiter。 + 建议: 将导入改为 org.junit.jupiter.api.Test(JUnit 5),并同步将 org.junit.Assert 迁移为 org.junit.jupiter.api.Assertions。 +- 🔴 `pmd:WrongTestAnnotation` L39 + org.junit.Test 是 JUnit 4 的注解,而当前代码库正在使用 JUnit Jupiter。 + 建议: 将导入改为 org.junit.jupiter.api.Test(JUnit 5),并同步将 org.junit.Assert 迁移为 org.junit.jupiter.api.Assertions。 +- 🔴 `pmd:WrongTestAnnotation` L47 + org.junit.Test 是 JUnit 4 的注解,而当前代码库正在使用 JUnit Jupiter。 + 建议: 将导入改为 org.junit.jupiter.api.Test(JUnit 5),并同步将 org.junit.Assert 迁移为 org.junit.jupiter.api.Assertions。 +- 🔴 `pmd:WrongTestAnnotation` L53 + org.junit.Test 是 JUnit 4 的注解,而当前代码库正在使用 JUnit Jupiter。 + 建议: 将导入改为 org.junit.jupiter.api.Test(JUnit 5),并同步将 org.junit.Assert 迁移为 org.junit.jupiter.api.Assertions。 +- 🔴 `pmd:AvoidThrowingNullPointerException` L63 + 避免抛出空指针异常。 + 建议: 不要显式 throw new NullPointerException();可改用 java.util.Objects.requireNonNull(null) 产生 NPE,或改抛更具体的异常并同步调整测试期望。 +- 🔴 `pmd:WrongTestAnnotation` L69 + org.junit.Test 是 JUnit 4 的注解,而当前代码库正在使用 JUnit Jupiter。 + 建议: 将导入改为 org.junit.jupiter.api.Test(JUnit 5),并同步将 org.junit.Assert 迁移为 org.junit.jupiter.api.Assertions。 +- 🔴 `pmd:WrongTestAnnotation` L79 + org.junit.Test 是 JUnit 4 的注解,而当前代码库正在使用 JUnit Jupiter。 + 建议: 将导入改为 org.junit.jupiter.api.Test(JUnit 5),并同步将 org.junit.Assert 迁移为 org.junit.jupiter.api.Assertions。 +- 🟡 `pmd:AtLeastOneConstructor` L9 + 每个类都应声明至少一个构造函数。 + 建议: 为 JUnit4RulesTest 添加一个显式构造函数,避免依赖隐式公有无参构造器。 +- 🟡 `pmd:LocalVariableCouldBeFinal` L13 + 局部变量 'a' 可以声明为 final。 + 建议: 将该局部变量标记为 final,防止意外重新赋值并提升可读性。 +- 🟡 `pmd:LocalVariableCouldBeFinal` L14 + 局部变量 'b' 可以声明为 final。 + 建议: 将该局部变量标记为 final,防止意外重新赋值并提升可读性。 +- 🟡 `pmd:SimplifiableTestAssertion` L15 + 该断言可以使用 assertEquals 简化。 + 建议: 用 assertEquals(a, b) 代替 assertTrue(a.equals(b)),并补充失败消息;若迁移到 JUnit Jupiter,应为 Assertions.assertEquals(a, b)。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L15 + 单元测试断言应包含失败消息。 + 建议: 为断言增加第一个 String 参数作为失败消息,例如 assertEquals("a should equal b", a, b)。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L21 + 单元测试断言应包含失败消息。 + 建议: 为 assertEquals 补充失败消息,例如 assertEquals("expected value", expected, actual)。 +- 🟡 `pmd:UnitTestContainsTooManyAsserts` L26 + 单元测试不应包含超过 1 个断言。 + 建议: 将 testTooMany 拆分为多个测试方法,每个方法只保留一个断言;或使用 AssertJ 的软断言(assertSoftly)承载多个校验。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L27 + 单元测试断言应包含失败消息。 + 建议: 该断言本身无意义,建议删除;如果保留,必须提供消息,例如 assertTrue("message", condition)。 +- 🟡 `pmd:UnnecessaryBooleanAssertion` L27 + assertTrue(true) 或类似语句是不必要的。 + 建议: 删除对布尔常量 true 的断言;若需要固定验证,应改为对实际被测状态的断言。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L28 + 单元测试断言应包含失败消息。 + 建议: 该断言本身无意义,建议删除;如果保留,必须提供消息,例如 assertTrue("message", condition)。 +- 🟡 `pmd:UnnecessaryBooleanAssertion` L28 + assertTrue(true) 或类似语句是不必要的。 + 建议: 删除对布尔常量 true 的断言;若需要固定验证,应改为对实际被测状态的断言。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L29 + 单元测试断言应包含失败消息。 + 建议: 该断言本身无意义,建议删除;如果保留,必须提供消息,例如 assertTrue("message", condition)。 +- 🟡 `pmd:UnnecessaryBooleanAssertion` L29 + assertTrue(true) 或类似语句是不必要的。 + 建议: 删除对布尔常量 true 的断言;若需要固定验证,应改为对实际被测状态的断言。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L30 + 单元测试断言应包含失败消息。 + 建议: 该断言本身无意义,建议删除;如果保留,必须提供消息,例如 assertTrue("message", condition)。 +- 🟡 `pmd:UnnecessaryBooleanAssertion` L30 + assertTrue(true) 或类似语句是不必要的。 + 建议: 删除对布尔常量 true 的断言;若需要固定验证,应改为对实际被测状态的断言。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L31 + 单元测试断言应包含失败消息。 + 建议: 为 assertEquals 增加失败消息,例如 assertEquals("1 should equal 1", 1, 1)。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L32 + 单元测试断言应包含失败消息。 + 建议: 为 assertEquals 增加失败消息,例如 assertEquals("2 should equal 2", 2, 2)。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L33 + 单元测试断言应包含失败消息。 + 建议: 为 assertEquals 增加失败消息,例如 assertEquals("3 should equal 3", 3, 3)。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L34 + 单元测试断言应包含失败消息。 + 建议: 为 assertEquals 增加失败消息,例如 assertEquals("4 should equal 4", 4, 4)。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L35 + 单元测试断言应包含失败消息。 + 建议: 为 assertEquals 增加失败消息,例如 assertEquals("5 should equal 5", 5, 5)。 +- 🟡 `pmd:LocalVariableCouldBeFinal` L41 + 局部变量 'actual' 可以声明为 final。 + 建议: 将该局部变量标记为 final,防止意外重新赋值并提升可读性。 +- 🟡 `pmd:LocalVariableCouldBeFinal` L42 + 局部变量 'expected' 可以声明为 final。 + 建议: 将该局部变量标记为 final,防止意外重新赋值并提升可读性。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L43 + 单元测试断言应包含失败消息。 + 建议: 为 assertEquals 增加失败消息,并同时修正参数顺序:assertEquals("expected should equal actual", expected, actual)。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L49 + 单元测试断言应包含失败消息。 + 建议: 该断言本身无意义,建议删除;如果保留,必须提供消息,例如 assertTrue("message", condition)。 +- 🟡 `pmd:UnnecessaryBooleanAssertion` L49 + assertTrue(true) 或类似语句是不必要的。 + 建议: 删除对布尔常量 true 的断言;若需要固定验证,应改为对实际被测状态的断言。 +- 🟡 `pmd:JUnitUseExpected` L55 + 在 JUnit4 中,应使用 @Test(expected) 标注预期会抛出异常的测试。 + 建议: 若使用 JUnit 4,改为 @Test(expected = NullPointerException.class) 并删除 try/catch;若已迁移到 JUnit Jupiter,使用 assertThrows(NullPointerException.class, () -> doSomething())。 +- 🟡 `pmd:EmptyCatchBlock` L58 + 避免空 catch 块。 + 建议: 不要在 catch 块中留空;应使用 assertThrows 或 @Test(expected) 声明预期异常,或至少记录异常并重新抛出。 +- 🟡 `pmd:AvoidCatchingGenericException` L58 + 避免在 try-catch 块中捕获 NullPointerException。 + 建议: 不要捕获并吞掉 NPE;在 JUnit Jupiter 下应使用 assertThrows 声明预期异常,而非手写 try/catch。 +- 🟡 `pmd:AtLeastOneConstructor` L68 + 每个类都应声明至少一个构造函数。 + 建议: 为 MissingAfterTest 添加一个显式构造函数。 +- 🟡 `pmd:PublicMemberInNonPublicType` L70 + 公共成员 'testCleanup' 声明在非公共类型中。 + 建议: 如果使用 JUnit Jupiter,可去掉 public 修饰;如果保留 JUnit 4,应将测试类声明为 public。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L71 + 单元测试断言应包含失败消息。 + 建议: 该断言本身无意义,建议删除;如果保留,必须提供消息,例如 assertTrue("message", condition)。 +- 🟡 `pmd:UnnecessaryBooleanAssertion` L71 + assertTrue(true) 或类似语句是不必要的。 + 建议: 删除对布尔常量 true 的断言;若需要固定验证,应改为对实际被测状态的断言。 +- 🟡 `pmd:UnitTestShouldUseAfterAnnotation` L73 + 如果此方法用于测试清理,请使用正确的注解。 + 建议: 在 JUnit Jupiter 中使用 @AfterEach,在 JUnit 4 中使用 @After,并补充清理逻辑或删除空方法。 +- 🟡 `pmd:DetachedTestCase` L73 + 可能是脱离的 JUnit 测试用例。 + 建议: 该方法名容易让 JUnit 误认为它是测试用例,但未使用生命周期注解;如果用于清理,请添加 @AfterEach/@After;否则删除或重命名。 +- 🟡 `pmd:PublicMemberInNonPublicType` L73 + 公共成员 'tearDown' 声明在非公共类型中。 + 建议: 如果使用 JUnit Jupiter,可去掉 public 修饰;如果保留 JUnit 4,应将测试类声明为 public。 +- 🟡 `pmd:AtLeastOneConstructor` L78 + 每个类都应声明至少一个构造函数。 + 建议: 为 MissingBeforeTest 添加一个显式构造函数。 +- 🟡 `pmd:PublicMemberInNonPublicType` L80 + 公共成员 'testSetup' 声明在非公共类型中。 + 建议: 如果使用 JUnit Jupiter,可去掉 public 修饰;如果保留 JUnit 4,应将测试类声明为 public。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L81 + 单元测试断言应包含失败消息。 + 建议: 该断言本身无意义,建议删除;如果保留,必须提供消息,例如 assertTrue("message", condition)。 +- 🟡 `pmd:UnnecessaryBooleanAssertion` L81 + assertTrue(true) 或类似语句是不必要的。 + 建议: 删除对布尔常量 true 的断言;若需要固定验证,应改为对实际被测状态的断言。 +- 🟡 `pmd:UnitTestShouldUseBeforeAnnotation` L83 + 如果此方法用于测试初始化,请使用正确的注解。 + 建议: 在 JUnit Jupiter 中使用 @BeforeEach,在 JUnit 4 中使用 @Before,并补充初始化逻辑或删除空方法。 +- 🟡 `pmd:DetachedTestCase` L83 + 可能是脱离的 JUnit 测试用例。 + 建议: 该方法名容易让 JUnit 误认为它是测试用例,但未使用生命周期注解;如果用于初始化,请添加 @BeforeEach/@Before;否则删除或重命名。 +- 🟡 `pmd:PublicMemberInNonPublicType` L83 + 公共成员 'setUp' 声明在非公共类型中。 + 建议: 如果使用 JUnit Jupiter,可去掉 public 修饰;如果保留 JUnit 4,应将测试类声明为 public。 +- 🟡 `pmd:AtLeastOneConstructor` L88 + 每个类都应声明至少一个构造函数。 + 建议: 为 MissingTestAnnotationTest 添加一个显式构造函数。 +- 🟡 `pmd:TestClassWithoutTestCases` L88 + 类 'MissingTestAnnotationTest' 可能是测试类,但它不包含任何测试用例。 + 建议: 为该类添加一个带断言且标注 @Test 的测试方法;若只是 PMD 反例,可删除该类。 +- 🟡 `pmd:PublicMemberInNonPublicType` L89 + 公共成员 'testSomething' 声明在非公共类型中。 + 建议: 如果使用 JUnit Jupiter,可去掉 public 修饰;如果保留 JUnit 4,应将测试类声明为 public。 +- 🟡 `pmd:UnitTestShouldUseTestAnnotation` L89 + 单元测试应使用 @Test 注解,否则不会运行;在 JUnit Jupiter 中也可以使用 @RepeatedTest、@TestFactory、@TestTemplate 或 @ParameterizedTest。 + 建议: 在 testSomething 方法上添加 @org.junit.jupiter.api.Test(如果迁移到 Jupiter)或 org.junit.Test(如果保留 JUnit 4),并在方法内补充断言。 +- 🟡 `pmd:AtLeastOneConstructor` L94 + 每个类都应声明至少一个构造函数。 + 建议: 为 SpellingTest 添加一个显式构造函数。 +- 🟡 `pmd:TestClassWithoutTestCases` L94 + 类 'SpellingTest' 可能是测试类,但它不包含任何测试用例。 + 建议: 为 SpellingTest 补充真正的测试方法,并将 setup/teardown 改为带 @BeforeEach/@AfterEach 的 setUp/tearDown。 +- 🟡 `pmd:PublicMemberInNonPublicType` L95 + 公共成员 'setup' 声明在非公共类型中。 + 建议: 如果使用 JUnit Jupiter,可去掉 public 修饰;如果保留 JUnit 4,应将测试类声明为 public。 +- 🟡 `pmd:PublicMemberInNonPublicType` L97 + 公共成员 'teardown' 声明在非公共类型中。 + 建议: 如果使用 JUnit Jupiter,可去掉 public 修饰;如果保留 JUnit 4,应将测试类声明为 public。 +- 🟡 `pmd:UseUtilityClass` L102 + 所有成员都是静态的。考虑添加私有无参构造函数以防止实例化。 + 建议: 如果 StaticSuiteTest 只是工具类,应添加私有无参构造器;如果它是测试套件,应改用 @RunWith(Suite.class) 与 @SuiteClasses 并删除静态 suite 方法。 +- 🟡 `pmd:TestClassWithoutTestCases` L102 + 类 'StaticSuiteTest' 可能是测试类,但它不包含任何测试用例。 + 建议: 如果 StaticSuiteTest 是套件类,应添加套件注解并引用真实测试类;否则删除或补充测试方法。 +- 🟡 `pmd:JUnit4SuitesShouldUseSuiteAnnotation` L103 + JUnit 4 通过注解声明测试套件,而不是通过 suite 方法。 + 建议: 使用 @RunWith(Suite.class) 和 @SuiteClasses 声明测试套件并删除 suite();若迁移到 JUnit Platform Suite,应使用 @Suite 注解。 +- 🟡 `pmd:PublicMemberInNonPublicType` L103 + 公共成员 'suite' 声明在非公共类型中。 + 建议: 如果保留 JUnit 4 suite 方法,应将该类声明为 public;如果使用注解套件,类同样应为 public。 +- 🟡 `pmd:UseUtilityClass` L109 + 所有成员都是静态的。考虑添加私有无参构造函数以防止实例化。 + 建议: 如果 SuiteClassTest 只是工具类,应添加私有无参构造器;如果它是测试套件,应改用注解式套件并删除静态 suite 方法。 +- 🟡 `pmd:TestClassWithoutTestCases` L109 + 类 'SuiteClassTest' 可能是测试类,但它不包含任何测试用例。 + 建议: 如果 SuiteClassTest 是套件类,应添加套件注解并引用真实测试类;否则删除或补充测试方法。 +- 🟡 `pmd:JUnit4SuitesShouldUseSuiteAnnotation` L110 + JUnit 4 通过注解声明测试套件,而不是通过 suite 方法。 + 建议: 使用 @RunWith(Suite.class) 和 @SuiteClasses 声明测试套件并删除 suite();若迁移到 JUnit Platform Suite,应使用 @Suite 注解。 +- 🟡 `pmd:PublicMemberInNonPublicType` L110 + 公共成员 'suite' 声明在非公共类型中。 + 建议: 如果保留 JUnit 4 suite 方法,应将该类声明为 public;如果使用注解套件,类同样应为 public。 + +AI 审查 · 7 条建议 + +- 🔴 [AI] [bug] `assertEquals-argument-order` L43 + **assertEquals 参数顺序颠倒,导致失败消息误导** + 第 43 行调用 Assert.assertEquals(actual, expected),把 actual 放在了 expected 参数位置。JUnit 的 assertEquals 期望第一个参数是 expected、第二个是 actual;当前写法在断言失败时会输出与实际相反的消息,且语义错误。 + 建议: 改为 assertEquals("expected should equal actual", expected, actual),并尽量给断言补充消息;若使用 JUnit Jupiter,应为 Assertions.assertEquals(expected, actual)。 +- 🔴 [AI] [bug] `suite-returns-null` L104 + **StaticSuiteTest.suite() 返回 null,测试套件运行时会触发空指针** + StaticSuiteTest.suite() 直接返回 null。JUnit 执行套件时会尝试遍历返回的 Test 对象,导致 NullPointerException。 + 建议: 删除 suite() 方法,改用 @RunWith(Suite.class) 和 @SuiteClasses({...});若保留 suite(),请返回非 null 的 TestSuite。 +- 🔴 [AI] [bug] `suite-returns-null` L111 + **SuiteClassTest.suite() 返回 null,测试套件运行时会触发空指针** + SuiteClassTest.suite() 直接返回 null。JUnit 执行套件时会尝试遍历返回的 Test 对象,导致 NullPointerException。 + 建议: 删除 suite() 方法,改用 @RunWith(Suite.class) 和 @SuiteClasses({...});若保留 suite(),请返回非 null 的 TestSuite。 +- 🟡 [AI] [design] `junit4-assert-usage` L7 + **迁移到 JUnit Jupiter 后仍使用 JUnit 4 的 Assert API** + 代码中仍导入并使用 org.junit.Assert(如 Assert.assertTrue、Assert.assertEquals、Assert.fail)。在 JUnit Jupiter 下应使用 org.junit.jupiter.api.Assertions,否则断言行为/异常类型与 JUnit 5 不一致,且容易造成依赖混乱。 + 建议: 将导入改为 import org.junit.jupiter.api.Assertions;,并把所有 Assert. 调用改为 Assertions.(或使用静态导入);同时确认 @Test 导入来自 org.junit.jupiter.api。 +- 🟡 [AI] [design] `tautological-assertions` L31 + **testTooMany 中的 assertEquals 只比较常量与自身,属于恒真断言** + 第 31-35 行的 assertEquals(1, 1)、(2, 2) 等断言只比较常量与自身,即使被测逻辑被删除或出错,测试也会通过。该类断言没有测试价值。 + 建议: 删除这些无意义断言,改为对被测逻辑设置明确的输入和预期输出;若只是 PMD 演示反例,可在注释中说明。 +- 🟡 [AI] [bug] `test-class-visibility` L68 + **多个测试类不是 public,若按 JUnit 4 运行将无法发现用例** + MissingAfterTest、MissingBeforeTest、MissingTestAnnotationTest、SpellingTest、StaticSuiteTest、SuiteClassTest 均为包级私有类。当前代码仍混用 JUnit 4 API,若按 JUnit 4 运行,非 public 测试类不会被识别;若按 JUnit Jupiter 运行,又需要先彻底移除 JUnit 4 API。 + 建议: 统一迁移到 JUnit Jupiter 并将测试类/方法改为包级私有,或保留 JUnit 4 并将所有测试类及测试方法声明为 public。 +- 🟡 [AI] [design] `junit-lifecycle-naming` L95 + **setup/teardown 拼写不符合 JUnit 生命周期方法命名** + SpellingTest 中 setup() 和 teardown() 缺少大写字母 P/D,JUnit 不会将它们识别为生命周期方法;若意图是初始化/清理,应命名为 setUp/tearDown 并添加 @BeforeEach/@AfterEach。 + 建议: 改为 public void setUp() 并加 @BeforeEach,public void tearDown() 并加 @AfterEach;同时为类添加真正的 @Test 方法。 diff --git a/data/demo-pmd/reports/JUnit5ArgOrderTest-review.md b/data/demo-pmd/reports/JUnit5ArgOrderTest-review.md new file mode 100644 index 0000000..13b6d23 --- /dev/null +++ b/data/demo-pmd/reports/JUnit5ArgOrderTest-review.md @@ -0,0 +1,55 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\errorprone\extra\JUnit5ArgOrderTest.java` +**语言:** java +**耗时:** 94.8s +**分析工具:** pmd + +--- + +总计: 12 | 错误: 2 | 警告: 8 | 建议: 2 + +静态分析 · 9 个问题 + +- 🔴 `pmd:SystemPrintln` L24 + 使用了 System.out / System.err。 + 建议: 移除该输出语句,或改用日志框架(如 java.util.logging、SLF4J)进行记录。 +- 🟡 `pmd:AtLeastOneConstructor` L10 + 每个类都应声明至少一个构造函数。 + 建议: 为类添加一个显式的构造函数,例如:`public JUnit5ArgOrderTest() {}`,或确保存在其他构造函数。 +- 🟡 `pmd:JUnitJupiterTestShouldBePackagePrivate` L10 + JUnit 5 测试类应为包私有(不要使用 public 修饰符)。 + 建议: 将 `public class JUnit5ArgOrderTest` 改为 `class JUnit5ArgOrderTest`,使测试类为包私有。 +- 🟡 `pmd:JUnitJupiterTestShouldBePackagePrivate` L12 + JUnit 5 测试方法应为包私有(不要使用 public 修饰符)。 + 建议: 将 `public void testX()` 改为 `void testX()`。 +- 🟡 `pmd:LocalVariableCouldBeFinal` L13 + 局部变量 `actual` 可以声明为 final。 + 建议: 在变量声明处添加 `final` 修饰符:`final String actual = next("foo");`。 +- 🟡 `pmd:AssertEqualsArgumentOrder` L14 + 此 assertEquals() 调用的 expected 和 actual 参数顺序颠倒了。 + 建议: 将期望值作为第一个参数,实际值作为第二个参数:`assertEquals("bar", actual);`。 +- 🟡 `pmd:UnitTestAssertionsShouldIncludeMessage` L14 + 单元测试断言应包含一个描述性消息。 + 建议: 为断言添加消息参数:`assertEquals(expected, actual, "消息内容");`,例如 `assertEquals("bar", actual, "next() 的返回值应等于 bar");`。 +- 🟡 `pmd:CommentDefaultAccessModifier` L17 + 方法 `next(String)` 缺少默认访问修饰符(包私有)的注释。 + 建议: 在方法前添加注释 `/* package */`,或者显式声明访问修饰符(如 `private`)。 +- 🟡 `pmd:MethodArgumentCouldBeFinal` L17 + 参数 `s` 未被赋值,可以声明为 final。 + 建议: 在参数类型前添加 `final`:`String next(final String s)`。 + +AI 审查 · 3 条建议 + +- 🔴 [AI] [bug] `wrong-test-expectation` L14 + **测试断言期望值与实际输入不匹配** + `next("foo")` 返回 `"foo"`(因为 `next` 直接返回参数),但断言期望值为 `"bar"`。即使把 assertEquals 参数顺序调整正确,`assertEquals("bar", actual)` 仍会失败,因为 `actual` 是 `"foo"`。请检查测试意图:要么将期望值改为 `"foo"`,要么让 `next` 方法产生 `"bar"` 作为结果。 + 建议: 如果 `next` 被设计为恒等函数,应将断言改为 `assertEquals("foo", actual)`;否则修改 `next` 的实现以返回预期值。 +- 🔵 [AI] [design] `method-can-be-static` L17 + **辅助方法可声明为 static** + `next(String)` 不访问任何实例字段或实例方法,应声明为 `static`,以更清晰地表达其无状态性,并避免实例持有。 + 建议: 将 `String next(String s)` 改为 `static String next(String s)`;调用处 `next("foo")` 在实例方法内仍可调用静态方法,无需修改。 +- 🔵 [AI] [design] `top-level-class-in-test-file` L22 + **测试文件中不应包含无关的顶层类** + `Junit5Main` 是一个独立的顶层类,包含 `main` 方法,却与测试类 `JUnit5ArgOrderTest` 放在同一个源文件中。这样会降低可读性,并可能导致构建工具扫描到非测试类。建议将 `Junit5Main` 移到单独的 `Junit5Main.java` 文件中。 + 建议: 将 `Junit5Main` 类移到独立文件,或将其从测试源集中移除。 diff --git a/data/demo-pmd/reports/JUnit5RulesTest-review.md b/data/demo-pmd/reports/JUnit5RulesTest-review.md new file mode 100644 index 0000000..898945c --- /dev/null +++ b/data/demo-pmd/reports/JUnit5RulesTest-review.md @@ -0,0 +1,63 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\com\demo\errorprone\extra\JUnit5RulesTest.java` +**语言:** java +**耗时:** 139.8s +**分析工具:** pmd + +--- + +总计: 14 | 错误: 2 | 警告: 11 | 建议: 1 + +静态分析 · 9 个问题 + +- 🔴 `pmd:SystemPrintln` L25 + 使用了 System.out/err 输出。 + 建议: 避免直接使用 System.out.println,建议使用日志框架(如 SLF4J/Log4j2)或 java.util.logging.Logger。例如:private static final Logger LOG = Logger.getLogger(JupiterMain.class.getName()); LOG.info("demo jupiter"); +- 🟡 `pmd:AtLeastOneConstructor` L9 + 每个类都应至少声明一个构造函数。 + 建议: 为类添加一个无参构造函数。由于当前是测试类,可添加 public JupiterPublicTest() {} 以消除警告。 +- 🟡 `pmd:JUnitJupiterTestShouldBePackagePrivate` L9 + JUnit 5 测试类应为包私有。 + 建议: 移除 public 修饰符,将 'public class JupiterPublicTest' 改为 'class JupiterPublicTest'。 +- 🟡 `pmd:JUnitJupiterTestShouldBePackagePrivate` L11 + JUnit 5 测试方法应为包私有。 + 建议: 移除 public 修饰符,将 'public void testPublic()' 改为 'void testPublic()'。 +- 🟡 `pmd:UnitTestShouldIncludeAssert` L11 + 该单元测试应包含 assert() 或 fail() 断言。 + 建议: 在测试方法体中添加断言,例如:org.junit.jupiter.api.Assertions.assertTrue(true)。如果测试业务逻辑,请断言实际返回值或状态。 +- 🟡 `pmd:AtLeastOneConstructor` L16 + 每个类都应至少声明一个构造函数。 + 建议: 为 JupiterPrivateTest 类添加一个包私有无参构造函数,例如:JupiterPrivateTest() {} +- 🟡 `pmd:UnusedPrivateMethod` L18 + 避免使用未使用的私有方法 'testPrivate()'。 + 建议: testPrivate 是私有方法且未被使用,但又标注了 @Test。建议将其改为包私有方法(移除 private),使其成为有效的测试方法;如果它是普通辅助方法,则应在类内调用或删除。 +- 🟡 `pmd:JUnitJupiterTestNoPrivateModifier` L18 + JUnit 测试方法不能是 private。 + 建议: 删除 private 修饰符,改为包私有:private void testPrivate() 改为 void testPrivate()。注意:私有测试方法会导致 JUnit 执行失败,而不是被忽略。 +- 🟡 `pmd:UnitTestShouldIncludeAssert` L18 + 该单元测试应包含 assert() 或 fail() 断言。 + 建议: 在 testPrivate 方法中加入断言,例如:org.junit.jupiter.api.Assertions.assertTrue(true)。同时建议将方法改为包私有。 + +AI 审查 · 5 条建议 + +- 🔴 [AI] [bug] `main-class-must-be-public` L23 + **主类 JupiterMain 不是 public,无法作为程序入口** + Java 应用程序入口要求主类是 public(且 main 方法为 public static void)。JupiterMain 为包私有类,使用 java JupiterMain 启动时 JVM 会报找不到 main 方法。若该类仅用于演示,也应提取为独立 public 类。 + 建议: 将 JupiterMain 提取到独立文件 JupiterMain.java,并将类声明改为 public class JupiterMain。当前文件中已有一个 public 类 JupiterPublicTest,不能同时存在两个 public 顶层类。 +- 🟡 [AI] [design] `one-top-level-class-per-file` L9 + **同一文件包含多个顶层类,降低可维护性** + 该文件中同时定义了 JupiterPublicTest、JupiterPrivateTest 和 JupiterMain 三个顶层类。虽然 Java 允许在一个 .java 文件中声明多个非 public 顶层类,但实践上每个类应单独一个文件,以提升可读性和可维护性,并避免外部包导入时的困惑。 + 建议: 将每个顶层类分别放入独立的 .java 文件中,并确保 public 类的文件名与其类名一致。 +- 🟡 [AI] [style] `class-naming-misleading` L16 + **类名 JupiterPrivateTest 与可见性语义不符** + Java 顶层类不能为 private。JupiterPrivateTest 实际是包私有类,但类名容易让人误以为它是 private;该类中的测试方法也恰好是 private,进一步造成混淆。 + 建议: 将类改名为 JupiterPackagePrivateTest 或类似不含 private 的名称,同时将私有测试方法改为包私有。 +- 🟡 [AI] [bug] `misleading-comment-junit-private` L18 + **注释称私有测试方法不会执行,与 JUnit 5 实际行为不符** + 代码注释写着 'private 测试方法,不会执行',但 JUnit Jupiter 的 @Test 方法声明为 private 时,JUnit 会在运行时报告测试失败(JUnitException),而不是忽略。这种错误注解会误导开发者。 + 建议: 更新注释为准确描述,并将测试方法改为包私有,确保其被 JUnit 执行。 +- 🔵 [AI] [style] `test-method-naming` L11 + **测试方法名 testPublic 不具描述性** + 测试方法名仅表达了'公开',未反映被测试的行为或预期结果。好的测试命名应说明场景和预期,例如 shouldReturnXWhenY。 + 建议: 将方法重命名为更具行为描述性的名称,例如 shouldReturnExpectedValue()。 diff --git a/data/demo-pmd/reports/JspFix-review.md b/data/demo-pmd/reports/JspFix-review.md new file mode 100644 index 0000000..02700d0 --- /dev/null +++ b/data/demo-pmd/reports/JspFix-review.md @@ -0,0 +1,146 @@ +# 代码审查报告 + +**文件:** `data\demo-pmd\src\jsp\JspFix.jsp` +**语言:** html +**耗时:** 204.4s +**分析工具:** jsp + +--- + +总计: 42 | 错误: 6 | 警告: 36 | 建议: 0 + +静态分析 · 38 个问题 + +- 🔴 `pmd:NoLongScripts` L8 + 第 8 行:避免在 JSP 文件中包含较长的脚本(如 JavaScript)。 + 建议: 将 JavaScript 移至外部文件,创建 js/demo.js 并放入两个函数,用 替换整个内联