# 代码审查报告 **文件:** `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 并在业务中使用。若采用配置注入,也应确保字段被消费。