静态分析代码质量开发工具【免费下载链接】error-proneCatch common Java mistakes as compile-time errors项目地址https://gitcode.com/gh_mirrors/er/error-prone点击查看免费下载导读本文介绍 Error Proneerror-prone内置检查器TryWithResourcesVariable当代码把资源先赋值给一个final或有效 finaleffectively-final变量再在try-with-resources中用另一个变量去包装它时该检查器会提示这层包装是多余的并自动将其重构为 Java 9 引入的资源引用变量写法。读完本文你将掌握该检查器的匹配规则、自动修复行为、启用/抑制方式以及它在当前仓库中的完整源码实现与测试证据。Java 9 带来的写法变化资源可以是变量引用从 Java 9 开始try-with-resources语句中的资源不再必须是声明式资源即紧跟类型的变量声明也可以是对一个final或有效 final变量的引用。这意味着AutoCloseable resource ...; try (resource) { // Java 9 合法写法 doSomething(resource); }在 Java 9 之前上面的写法是不合法的开发者被迫多写一层搬运变量AutoCloseable resource ...; try (AutoCloseable resource2 resource) { // 多余的包装变量 doSomething(resource2); }第二种写法不仅在语法上多出一个变量还容易造成命名混乱——resource2与resource指向同一个对象却被当作两个不同的资源对待。TryWithResourcesVariable检查器的作用正是发现这类多余的包装变量并把它改写成第一种更简洁的写法。需要特别强调的是该检查器并不改变变量的作用域语义被引用的变量在try块执行完毕后依然存在只是不再拥有资源生命周期资源的关闭仍然由try-with-resources语句负责。检查器能发现什么匹配规则与边界根据关联文档 TryWithResourcesVariable.md 的说明该检查器只针对一种非常具体的模式try的资源列表里出现Type x identifier;形式的变量声明且初始化的identifier是一个final或有效 final的变量。文档同时给出了一个重要边界资源不能是任意表达式例如try (returnsTheResources()) { ... }这种写法仍然是不允许的。也就是说检查器不会也无法把任意表达式改写成资源引用——资源引用必须是某个已存在的、可被 Java 语义判定为 final/有效 final 的变量而不是方法调用、字段访问或其他表达式的结果。这也是它只匹配IdentifierTree标识符而不匹配其他表达式的原因。源码实现剖析matchTry 的四步判定检查器主体位于 TryWithResourcesVariable.java。它实现TryTreeMatcher核心逻辑在matchTry方法中对每个try语句做如下四步判定对应 TryWithResourcesVariable.java#L45-L67遍历资源列表for (Tree resource : tree.getResources())逐一检查try (...)括号里的每个资源。必须是变量声明资源必须是VariableTree即Type name ...的声明形式如果已经是try (resource)这种纯引用形式则跳过。初始化器必须是标识符initializer instanceof IdentifierTree排除方法调用、成员访问、字面量等一切其他表达式。符号必须被视为 final调用ASTHelpers.isConsideredFinal(getSymbol(initializer))确认被引用变量是final或有效 final。第四步判定的底层实现在 ASTHelpers.java 的isConsideredFinal方法ASTHelpers.java#L1917-L1920/** Returns whether {code symbol} is final or effectively final. */ public static boolean isConsideredFinal(Symbol symbol) { return (symbol.flags() (Flags.FINAL | Flags.EFFECTIVELY_FINAL)) ! 0; }该方法同时检查Flags.FINAL显式final与Flags.EFFECTIVELY_FINAL编译器推导出的有效 final即变量只被赋值一次两个标志位。因此即使变量没有写final关键字只要它从未被重新赋值检查器同样会认为它符合条件。检查器自身的BugPattern注解TryWithResourcesVariable.java#L38-L42声明如下BugPattern( summary This variable is unnecessary, the try-with-resources resource can be a reference to a final or effectively final variable, severity WARNING)诊断级别为WARNING触发时会给出提示该变量是多余的try-with-resources的资源可以直接引用这个 final/有效 final 变量。自动修复替换声明并重命名所有引用检查器并非只报告问题它还会生成一份可直接应用的SuggestedFix自动修复由两部分合并而成TryWithResourcesVariable.java#L61-L64SuggestedFix.builder() .replace(getStartPosition(variableTree), state.getEndPosition(initializer), name) .merge(SuggestedFixes.renameVariableUsages(variableTree, name, state)) .build()).replace(...)把Type name initializer整段声明替换为被引用变量的名字name即try (AutoCloseable r2 r1)→try (r1)。.merge(SuggestedFixes.renameVariableUsages(...))把原包装变量在try块内部的所有使用处一并重命名为被引用变量例如System.err.println(r2)→System.err.println(r1)从而消除对已消失包装变量的悬空引用。因此开发者只需要在编译产物中应用 Error Prone 给出的修复或在 IDE 中接受建议就能一键完成重构。测试验证三种典型场景当前仓库的测试位于 TryWithResourcesVariableTest.java使用BugCheckerRefactoringTestHelper做输入/输出对比测试覆盖三个典型场景单变量重构TryWithResourcesVariableTest.java#L30-L58// 输入 void f(AutoCloseable r1) { try (AutoCloseable r2 r1) { System.err.println(r2); } catch (Exception e) {} } // 输出 void f(AutoCloseable r1) { try (r1) { System.err.println(r1); } catch (Exception e) {} }多变量同时重构TryWithResourcesVariableTest.java#L60-L92try (AutoCloseable b1 a1; AutoCloseable b2 a2)会被同时改写为try (a1; a2)说明检查器对资源列表中的每个资源独立判定。非 final 变量保持不变TryWithResourcesVariableTest.java#L94-L114当被引用的变量r1在进入try之前被重新赋值r1 reassign(r1);它不再是有效 final测试断言expectUnchanged()——检查器不产生任何修改。这正对应了第 4 步判定中isConsideredFinal返回false的情况。启用方式默认关闭按需打开需要特别留意的是该检查器在 Error Prone 中默认不启用。查看内置检查器注册表 BuiltInCheckerSuppliers.javaTryWithResourcesVariable.class被列在DISABLED_CHECKS默认关闭的检查列表中BuiltInCheckerSuppliers.java#L1237-L1362。这类检查通常属于代码风格优化Style/Simplification 范畴不影响运行时正确性因此默认不打扰开发者。按 Error Prone 的命令行规则可以通过编译器的-Xep系列参数启用它# 以默认级别WARNING启用 -Xep:TryWithResourcesVariable # 显式指定级别启用 -Xep:TryWithResourcesVariable:WARN # 配合全局关闭再选择性开启例如仅允许该检查 -XepDisableAllChecks -Xep:TryWithResourcesVariable:WARN在 Maven 等构建工具中可将上述参数配置到maven-compiler-plugin的compilerArgs中使用 Bazel 构建时则通过--jvmopt或javacopts传入对应的-Xep参数。抑制方式如果某个位置确实想保留包装变量例如刻意缩小资源引用的作用域可以在类、方法或变量声明上使用SuppressWarnings(TryWithResourcesVariable)来抑制该检查检查名取自BugPattern注解未显式指定name时即用类名SuppressWarnings(TryWithResourcesVariable) void keepWrapper(AutoCloseable r1) { try (AutoCloseable r2 r1) { ... } }总结TryWithResourcesVariable是一个小而精准的 Java 9 时代语法现代化检查器它只针对用Type x identifier;包装 final/有效 final 变量作为 try-with-resources 资源这一种模式给出WARNING级别的提示并提供包含引用重命名的完整自动修复。它默认关闭需通过-Xep:TryWithResourcesVariable显式启用。其匹配逻辑、final 判定与修复生成分别依赖TryTreeMatcher、ASTHelpers.isConsideredFinal与SuggestedFixes.renameVariableUsages整体实现紧凑、行为被三个针对性的重构测试精确锁定适合作为理解 Error Prone 检查器匹配—判定—修复工作流的入门案例。赞分享静态分析代码质量开发工具【免费下载链接】error-proneCatch common Java mistakes as compile-time errors项目地址https://gitcode.com/gh_mirrors/er/error-prone点击查看免费下载相关推荐Error Prone 检查 ClosingStandardOutputStreams警惕 try-with-resources 悄悄关闭 System.out / System.errError Prone 检查 ClosingStandardOutputStreams警惕 try with resources 悄悄关闭 System.ou静态分析代码质量开发工具QuickRecorder macOS 录屏3 分钟装好文件小 40%QuickRecorder macOS 录屏3 分钟装好文件小 40% 录一段 10 分钟的教程文件 800MB发群里传了半小时。卡住的往往不是怎么录静态分析代码质量开发工具Error Prone 的 AutoValueFinalMethods 检查器为 AutoValue 类的 equals / hashCode / toString 添加 final 修饰Error Prone 的 AutoValueFinalMethods 检查器为 AutoValue 类的 equals / hashCode / toStr静态分析代码质量开发工具上一篇Umi-OCR5步轻松实现扫描PDF转可搜索文档的终极指南下一篇Rack Mini Profiler 使用教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考