
本文详解如何基于 Checkstyle 的 LeftCurlyCheck 扩展实现自定义检查——要求 Java 中每个 { 后必须紧随一个空白行,支持类、方法、if/for 等任意嵌套层级,解决常见“仅校验顶层结构”的局限性。
本文详解如何基于 checkstyle 的 `leftcurlycheck` 扩展实现自定义检查——要求 java 中每个 `{` 后必须紧随一个空白行,支持类、方法、if/for 等任意嵌套层级,解决常见“仅校验顶层结构”的局限性。
Checkstyle 默认的 LeftCurly 检查(如 nl 风格)仅关注左花括号的位置(换行/同行),但不校验其后一行是否为空白行。要实现“{ 后必须是空行”这一严格格式规范,最稳健的方式是继承并扩展官方 LeftCurlyCheck,而非从零遍历 token 或解析原始文件内容——后者易受 AST 层级限制(如仅触发 CLASS_DEF 而忽略 METHOD_DEF),且难以精准定位物理行号与上下文关系。
✅ 正确实现路径:复用并增强 LeftCurlyCheck
-
继承
LeftCurlyCheck类(而非AbstractCheck),复用其成熟的 brace 定位逻辑和 AST 遍历机制; -
重写
verifyBrace方法,在已知{token 位置的基础上,获取其所在行的下一行内容进行空白判断; -
通过
getLine()获取源码行,避免手动计算行号偏移错误。
以下是核心代码示例(兼容 Checkstyle 8.x–10.x):
public class BlankLineAfterLeftCurlyCheck extends LeftCurlyCheck {
@Override
protected void verifyBrace(DetailAST ast, int braceLineNo, int braceColNo) {
final int nextLineNo = braceLineNo;
final String[] lines = getLines();
if (nextLineNo < lines.length) {
final String nextLine = lines[nextLineNo].trim();
if (!nextLine.isEmpty()) {
log(braceLineNo + 1, "blank.line.after.left.curly",
"Left curly brace must be followed by a blank line");
}
}
}
@Override
public int[] getDefaultTokens() {
return new int[]{TokenTypes.LITERAL_TRY, TokenTypes.LITERAL_CATCH,
TokenTypes.LITERAL_FINALLY, TokenTypes.LITERAL_IF, TokenTypes.LITERAL_ELSE,
TokenTypes.LITERAL_FOR, TokenTypes.LITERAL_WHILE, TokenTypes.LITERAL_DO,
TokenTypes.SLIST, TokenTypes.OBJBLOCK, TokenTypes.METHOD_DEF,
TokenTypes.CTOR_DEF, TokenTypes.STATIC_INIT, TokenTypes.INSTANCE_INIT,
TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF, TokenTypes.ENUM_DEF,
TokenTypes.ANNOTATION_DEF, TokenTypes.RECORD_DEF};
}
}⚠️ 注意事项:
getLines()返回的是 0-indexed 行数组,而braceLineNo是 1-indexed(Checkstyle 标准),因此{所在行为braceLineNo - 1,其下一行物理行号即为braceLineNo(对应lines[braceLineNo]);- 必须在
getDefaultTokens()中显式包含所有需校验的 AST 节点类型(如METHOD_DEF,IF,FOR等),否则嵌套结构将被跳过;- 在
checkstyle.xml中注册时,仍置于<module name="TreeWalker"></module>下,无需额外配置FileContentsHolder——getLines()已由父类自动注入。
✅ IntelliJ 集成提示
- 编译生成 JAR 后,在 IntelliJ 的 Checkstyle 插件设置中指定该 JAR 路径;
-
checkstyle.xml示例片段:<module name="TreeWalker"> <module name="BlankLineAfterLeftCurlyCheck"/> </module> - 若遇
ClassNotFoundException,请确认 JAR 包含module-info.class(Checkstyle 10+)或已正确打包依赖(推荐使用maven-shade-plugin合并)。
✅ 总结
绕过低层 token 遍历或文件行扫描的“捷径”,转而深度复用 Checkstyle 原生检查器的设计范式,是开发健壮、可维护、全层级生效的自定义规则的关键。本方案不仅满足“{ 后空行”的业务需求,更具备良好的可扩展性——例如后续可增加白名单(如 if (x) { 允许单行)、或支持跳过注释块等高级策略。

















