Checkstyle
相关工具推荐
| 工具 | 说明 |
|---|---|
| PMD | Java 静态代码分析工具,侧重潜在缺陷与不良实践检测 |
| SpotBugs | Java 字节码级缺陷检测工具,基于 Bug Patterns 发现问题 |
| Google-Java-Format | Google 出品的 Java 代码格式化工具,与 Google Java Style Guide 配合使用 |
| Spotless | 多语言代码格式化统一框架,支持 Maven/Gradle 集成 |
1. 简介
Checkstyle 是一款面向 Java 语言的开源静态代码分析工具,由 Oliver Burn 于 2001 年创建,是 Java 生态中代码风格与规范检查的主流工具之一。它通过解析 Java 源代码的抽象语法树(AST),结合预定义或自定义的规则集,对代码进行逐行、逐方法、逐类级别的合规性扫描与报告生成。
- 主要检查语言:Java
- 主要检查能力:检测 Java 代码风格、命名规范、Javadoc 注释、代码复杂度、导入语句、代码块结构等;涵盖代码风格检查、编码规范检查、代码复杂度检查
- 核心检查原理:基于 ANTLR4 解析 Java 源码生成 AST,采用 Visitor 模式遍历 AST 节点执行检查
- 检查规则/选项:约 180+ 项标准检查(按 naming、coding、design、imports、javadoc、whitespace 等类别组织),全量规则列表
- GitHub 仓库:https://github.com/checkstyle/checkstyle(8,948 stars)
- 开源协议:LGPL-2.1-or-later
- 最新稳定版本:v10.21.4
- 运行环境要求:13.x 需 JRE 21+,11.x/12.x 需 JRE 17+,10.x 需 JRE 11+,7.x-9.x 需 JRE 8+;支持解析 Java 22 及以下版本的所有语言特性
- 误报率:低
2. 官方文档
| 资源 | 链接 |
|---|---|
| 官方网站 | https://checkstyle.org/ |
| 配置文件说明 | https://checkstyle.org/config.html |
| 所有检查规则一览 | https://checkstyle.org/checks.html |
| 命令行使用文档 | https://checkstyle.org/cmdline.html |
| 过滤器(Filters)文档 | https://checkstyle.org/config_filters.html |
| 文件过滤器文档 | https://checkstyle.org/config_filefilters.html |
| 属性类型说明 | https://checkstyle.org/property_types.html |
| Ant 任务文档 | https://checkstyle.org/anttask.html |
| 样式配置说明(Google/Sun) | https://checkstyle.org/style_configs.html |
| Google Java Style 配置详情 | https://checkstyle.org/google_style.html |
| Sun Code Conventions 配置详情 | https://checkstyle.org/sun_style.html |
| 自定义检查开发指南 | https://checkstyle.org/writingchecks.html |
| 贡献指南 | https://checkstyle.org/contributing.html |
| GitHub Releases | https://github.com/checkstyle/checkstyle/releases |
| Maven Central 依赖 | https://central.sonatype.com/artifact/com.puppycrawl.tools/checkstyle |
| Google Java Style Guide(参考) | https://google.github.io/styleguide/javaguide.html |
3. 社区优秀实践
3.1 Spring Framework
Spring Framework 是 Java 生态中最具影响力的开源项目之一,在构建流程中深度集成了 Checkstyle。Spring 团队维护了自己的代码规范配置,基于 Google Java Style 进行了定制扩展,并通过 spring-javaformat 项目提供了配套的格式化工具。
- 仓库地址:https://github.com/spring-projects/spring-framework
- 规范配置位置:
src/checkstyle/checkstyle.xml - 特点:使用
spring-javaformat-checkstyle扩展模块,包含 SpringHeaderCheck(版权声明检查)、HideUtilityClassConstructor 等自定义规则 - Gradle 集成:通过
checkstyle插件在checkstyleMain/checkstyleTest任务中执行
// Spring Framework 的 build.gradle 中的 Checkstyle 配置片段
checkstyle {
toolVersion = "10.18.1"
configDir = file("src/checkstyle")
configProperties = [config_loc: file("src/checkstyle").absolutePath]
}
3.2 Apache Maven(maven-checkstyle-plugin)
Apache Maven 官方提供的 maven-checkstyle-plugin 是 Checkstyle 在 Java 构建生态中应用最广泛的集成方式。该插件内置了 maven_checks.xml 配置文件,专门用于 Maven 插件和组件的代码规范检查,是 Maven 项目接入 Checkstyle 的首选方案。
- 仓库地址:https://github.com/apache/maven-checkstyle-plugin
- 内置规范:
maven_checks.xml(Maven 项目专用规范) - 特点:与 Maven 生命周期深度绑定,支持在
validate、verify等阶段自动执行检查,可生成 XML/HTML 格式的检查报告
<!-- Maven 项目中使用内置 maven_checks.xml -->
<configuration>
<configLocation>maven_checks.xml</configLocation>
</configuration>
3.3 Google Guava
Google Guava 是 Google 开源的核心 Java 库,严格遵循 Google Java Style Guide,使用 Checkstyle 进行代码规范强制检查。Google 维护的 google_checks.xml 是 Checkstyle 内置的两大标准配置之一,被广泛作为 Java 项目的规范基线。
- 仓库地址:https://github.com/google/guava
- 规范配置:
google_checks.xml(Checkstyle 内置) - 特点:严格遵循 Google Java Style Guide,包括命名规范、缩进(2 空格)、行长度限制(100 字符)、Javadoc 要求等
- 配置文件源码:https://github.com/checkstyle/checkstyle/blob/master/src/main/resources/google_checks.xml
4. 工具配置说明
以下推荐两种方案:一是直接使用 Google Java Style 配置(开箱即用),二是基于 Google 规范定制的团队配置(推荐)。
4.1 配置文件说明
Checkstyle 提供三种内置的标准配置文件,均包含在 Checkstyle 的 JAR 包中,同时支持自定义 XML 配置文件:
| 配置文件 | 用途 | 使用场景 |
|---|---|---|
google_checks.xml |
基于 Google Java Style Guide 的内置配置 | 通用项目,推荐大多数团队使用 |
sun_checks.xml |
基于 Sun Code Conventions 的内置配置 | 传统 Java 项目 |
maven_checks.xml |
Maven 项目专用规范 | Apache Maven 插件/组件开发 |
checkstyle.xml |
自定义团队规范配置 | 需要定制规则的项目,放置在 config/checkstyle/ 目录下 |
配置文件源码位置:
google_checks.xml:https://github.com/checkstyle/checkstyle/blob/master/src/main/resources/google_checks.xmlsun_checks.xml:https://github.com/checkstyle/checkstyle/blob/master/src/main/resources/sun_checks.xml
4.2 checkstyle.xml 配置详解
Checkstyle 配置文件采用 XML 格式,根元素为 <module name="Checker">,通过嵌套 <module> 定义检查规则,通过 <property> 配置规则参数。
配置项说明(Checker 模块属性):
| 配置项 | 类型 | 说明 |
|---|---|---|
charset |
string | 配置文件使用的字符编码 |
severity |
string | 违规严重级别(error、warning、info),设为 error 时违规会导致构建失败 |
fileExtensions |
string | 检查的文件扩展名列表(逗号分隔) |
自定义配置文件最小示例:
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<property name="charset" value="UTF-8"/>
<property name="fileExtensions" value="java, properties, xml"/>
<property name="severity" value="error"/>
<!-- 排除 module-info.java -->
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="module\-info\.java$"/>
</module>
<!-- 引入抑制规则文件 -->
<module name="SuppressionFilter">
<property name="file" value="${config_loc}/checkstyle-suppressions.xml"/>
<property name="optional" value="true"/>
</module>
<!-- 文件级检查 -->
<module name="FileTabCharacter"/>
<module name="LineLength">
<property name="fileExtensions" value="java"/>
<property name="max" value="120"/>
</module>
<!-- AST 级检查 -->
<module name="TreeWalker">
<module name="PackageName"/>
<module name="TypeName"/>
<module name="MethodName"/>
<module name="MemberName"/>
<module name="ParameterName"/>
<module name="ConstantName"/>
</module>
</module>
推荐配置方案:
方案一:直接使用 Google Java Style
Google Java Style 是 Checkstyle 内置的标准配置,开箱即用,适合大多数 Java 项目。通过 --config 参数或构建工具的 configLocation 指定 google_checks.xml 即可启用。
Google Checks 的主要规则包括:
- 行长度限制 100 字符
- 缩进使用 2 个空格
- 命名规范:类名 UpperCamelCase、方法名 lowerCamelCase、常量 UPPER_SNAKE_CASE、包名全小写
- 禁止星号导入(
import *) - Javadoc 要求:public 方法必须有 Javadoc
- 代码块风格:K&R 风格(左大括号不换行)
方案二:基于 Google 规范的团队定制配置(推荐)
以下是一个基于 Google Java Style 优化后的团队配置文件,放宽了部分严格规则,增加了实用性检查。
config/checkstyle/checkstyle.xml:
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<!--
基于 Google Java Style Guide 的团队定制 Checkstyle 配置。
参考规范:https://google.github.io/styleguide/javaguide.html
官方文档:https://checkstyle.org
-->
<module name="Checker">
<!-- 启用 @SuppressWarnings 注解抑制 -->
<module name="SuppressWarningsFilter"/>
<!-- 字符编码 -->
<property name="charset" value="UTF-8"/>
<!-- 违规严重级别设为 error,使构建在检查出问题时失败 -->
<property name="severity" value="error"/>
<!-- 检查的文件类型 -->
<property name="fileExtensions" value="java, properties, xml"/>
<!-- 排除 module-info.java 文件 -->
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="module\-info\.java$"/>
</module>
<!-- 引入外部抑制规则文件 -->
<module name="SuppressionFilter">
<property name="file" value="${config_loc}/checkstyle-suppressions.xml"
default="config/checkstyle/checkstyle-suppressions.xml"/>
<property name="optional" value="true"/>
</module>
<!-- ========== 文件级检查 ========== -->
<!-- 禁止使用 Tab 字符,强制使用空格缩进 -->
<module name="FileTabCharacter">
<property name="eachLine" value="true"/>
</module>
<!-- 行长度限制 120 字符(Google 默认 100,团队放宽至 120) -->
<module name="LineLength">
<property name="fileExtensions" value="java"/>
<property name="max" value="120"/>
<property name="ignorePattern"
value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
</module>
<!-- 文件末尾必须有换行符 -->
<module name="NewlineAtEndOfFile"/>
<!-- 文件长度不超过 2000 行 -->
<module name="FileLength">
<property name="max" value="2000"/>
</module>
<!-- ========== AST 级检查(TreeWalker) ========== -->
<module name="TreeWalker">
<!-- 外部类型名称必须与文件名匹配 -->
<module name="OuterTypeFilename"/>
<!-- 禁止非法的字符串标记(禁止八进制转义和 Unicode 转义) -->
<module name="IllegalTokenText">
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
<property name="format"
value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
<property name="message"
value="禁止使用八进制转义或 Unicode 转义字符"/>
</module>
<!-- ========== 导入检查 ========== -->
<!-- 禁止星号导入 -->
<module name="AvoidStarImport"/>
<!-- 禁止冗余导入 -->
<module name="RedundantImport"/>
<!-- 禁止未使用的导入 -->
<module name="UnusedImports"/>
<!-- 禁止从 sun.* 包导入 -->
<module name="IllegalImport">
<property name="illegalPkgs" value="sun"/>
</module>
<!-- 导入语句排序:静态导入放在普通导入之后 -->
<module name="CustomImportOrder">
<property name="sortImportsInGroupAlphabetically" value="true"/>
<property name="separateLineBetweenGroups" value="true"/>
<property name="customImportOrderRules"
value="STATIC###THIRD_PARTY_PACKAGE"/>
</module>
<!-- ========== 命名检查 ========== -->
<!-- 常量名:全大写,单词间下划线分隔,如 MAX_COUNT -->
<module name="ConstantName">
<property name="format" value="^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"/>
</module>
<!-- 局部 final 变量名:camelCase,允许以大写字母开头 -->
<module name="LocalFinalVariableName">
<property name="format" value="^[a-z][a-zA-Z0-9]*$|^([A-Z][A-Z0-9]*(_[A-Z0-9]+)*$)"/>
</module>
<!-- 局部变量名:camelCase -->
<module name="LocalVariableName">
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
</module>
<!-- 成员变量名:camelCase -->
<module name="MemberName">
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
</module>
<!-- 方法名:camelCase -->
<module name="MethodName">
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
</module>
<!-- 包名:全小写 -->
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
</module>
<!-- 参数名:camelCase -->
<module name="ParameterName">
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
</module>
<!-- 类/接口名:UpperCamelCase -->
<module name="TypeName">
<property name="format" value="^[A-Z][a-zA-Z0-9]*$"/>
</module>
<!-- ========== 代码块检查 ========== -->
<!-- 空代码块检查 -->
<module name="EmptyBlock">
<property name="option" value="TEXT"/>
<property name="tokens" value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
</module>
<!-- 左大括号位置:不换行(K&R 风格) -->
<module name="LeftCurly">
<property name="tokens"
value="ANNOTATION_DEF, CLASS_DEF, CTOR_DEF, ENUM_CONSTANT_DEF, ENUM_DEF,
INTERFACE_DEF, LAMBDA, LITERAL_CASE, LITERAL_CATCH, LITERAL_DEFAULT,
LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF,
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE,
METHOD_DEF, OBJBLOCK, STATIC_INIT, RECORD_DEF, COMPACT_CTOR_DEF"/>
</module>
<!-- 右大括号位置 -->
<module name="RightCurly">
<property name="id" value="RightCurlySame"/>
<property name="tokens"
value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE,
LITERAL_DO"/>
</module>
<module name="RightCurly">
<property name="id" value="RightCurlyAlone"/>
<property name="option" value="alone"/>
<property name="tokens"
value="CLASS_DEF, CTOR_DEF, ENUM_DEF, INTERFACE_DEF, METHOD_DEF, RECORD_DEF,
COMPACT_CTOR_DEF, STATIC_INIT, RECORD_DEF, OBJBLOCK, LAMBDA"/>
</module>
<!-- 需要 else 时禁止省略大括号 -->
<module name="NeedBraces">
<property name="tokens"
value="LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_IF, LITERAL_WHILE"/>
</module>
<!-- ========== 空白符检查 ========== -->
<!-- 方法调用后空格检查 -->
<module name="MethodParamPad"/>
<!-- 圆括号内无空格 -->
<module name="ParenPad"/>
<!-- 运算符周围空格 -->
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true"/>
<property name="allowEmptyLambdas" value="true"/>
<property name="allowEmptyMethods" value="true"/>
<property name="allowEmptyTypes" value="true"/>
<property name="allowEmptyLoops" value="true"/>
<property name="tokens"
value="ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN,
BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, DO_WHILE, EQUAL,
GE, GT, LAMBDA, LAND, LCURLY, LE, LITERAL_RETURN, LT, MINUS,
MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN,
QUESTION, RCURLY, SL, SLIST, SL_ASSIGN, SR, SR_ASSIGN, STAR,
STAR_ASSIGN, LITERAL_ASSERT, TYPE_EXTENSION_AND"/>
</module>
<!-- 泛型中 > 后无空格,< 前无空格 -->
<module name="GenericWhitespace"/>
<!-- 数组定义风格:Java 风格 String[] args,而非 C 风格 String args[] -->
<module name="ArrayTypeStyle"/>
<!-- switch 语句中必须有 default -->
<module name="DefaultComesLast"/>
<!-- fall-through 检查 -->
<module name="FallThrough"/>
<!-- ========== 代码质量检查 ========== -->
<!-- 禁止使用 System.out 和 System.err,应使用日志框架 -->
<module name="Regexp">
<property name="format" value="System\.(out|err)\.print"/>
<property name="illegalPattern" value="true"/>
<property name="message" value="请使用 SLF4J 等日志框架替代 System.out/err"/>
</module>
<!-- long 类型字面量使用大写 L -->
<module name="UpperEll"/>
<!-- 禁止在 if/while 条件中使用赋值 -->
<module name="InnerAssignment"/>
<!-- 禁止空语句 -->
<module name="EmptyStatement"/>
<!-- ========== Javadoc 检查 ========== -->
<!-- public 方法必须有 Javadoc -->
<module name="JavadocMethod">
<property name="scope" value="public"/>
<property name="allowMissingParamTags" value="true"/>
<property name="allowMissingReturnTag" value="true"/>
</module>
<!-- public 类必须有 Javadoc -->
<module name="JavadocType">
<property name="scope" value="public"/>
</module>
<!-- ========== 修饰符检查 ========== -->
<!-- 修饰符顺序:public protected private abstract static final transient volatile synchronized native strictfp -->
<module name="ModifierOrder"/>
<!-- 冗余修饰符检查:确保接口方法不需要 public abstract -->
<module name="RedundantModifier"/>
</module>
</module>
配套的抑制规则文件 config/checkstyle/checkstyle-suppressions.xml:
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions>
<!-- 排除自动生成的代码 -->
<suppress files=".*[\\/]generated[\\/].*" checks=".*"/>
<suppress files=".*[\\/]generated-sources[\\/].*" checks=".*"/>
<!-- 排除测试代码的 Javadoc 检查 -->
<suppress files=".*Test\.java" checks="JavadocMethod"/>
<suppress files=".*Test\.java" checks="JavadocType"/>
<!-- 排除配置类的行长度检查 -->
<suppress files=".*Application\.java" checks="LineLength"/>
<!-- 排除常量类的魔法数字检查 -->
<suppress files=".*Constant(s)?\.java" checks="MagicNumber"/>
</suppressions>
4.3 规则说明对照表
| 规则模块 | 说明 | 默认值/配置 |
|---|---|---|
FileTabCharacter |
禁止使用 Tab 字符 | 每行检查 |
LineLength |
行长度限制 | 120 字符 |
NewlineAtEndOfFile |
文件末尾换行 | 必须有换行 |
FileLength |
文件长度限制 | 2000 行 |
AvoidStarImport |
禁止星号导入 | 禁止 import xxx.* |
RedundantImport |
禁止冗余导入 | 自动检测 |
UnusedImports |
禁止未使用的导入 | 自动检测 |
IllegalImport |
禁止非法包导入 | 禁止 sun.* |
CustomImportOrder |
导入排序 | 静态导入在普通导入之后 |
ConstantName |
常量命名 | ^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$ |
LocalVariableName |
局部变量命名 | ^[a-z][a-zA-Z0-9]*$ |
MemberName |
成员变量命名 | ^[a-z][a-zA-Z0-9]*$ |
MethodName |
方法命名 | ^[a-z][a-zA-Z0-9]*$ |
TypeName |
类/接口命名 | ^[A-Z][a-zA-Z0-9]*$ |
PackageName |
包名命名 | ^[a-z]+(\.[a-z][a-z0-9]*)*$ |
LeftCurly |
左大括号位置 | 不换行(K&R 风格) |
RightCurly |
右大括号位置 | 独占一行 |
NeedBraces |
必须使用大括号 | if/for/while/do-while |
WhitespaceAround |
运算符周围空格 | 必须有空格 |
GenericWhitespace |
泛型空白符 | <> 前后无空格 |
EmptyBlock |
空代码块 | 禁止(TEXT 模式) |
EmptyStatement |
空语句 | 禁止 |
FallThrough |
switch fall-through | 禁止无注释的 fall-through |
DefaultComesLast |
switch default 位置 | default 必须在最后 |
UpperEll |
long 类型字面量 | 必须使用大写 L |
ArrayTypeStyle |
数组声明风格 | Java 风格 String[] |
ModifierOrder |
修饰符顺序 | 按 Java 规范排序 |
Regexp |
正则表达式检查 | 禁止 System.out/err.print |
JavadocMethod |
方法 Javadoc | public 方法必须有 |
JavadocType |
类 Javadoc | public 类必须有 |
5. 主流集成方式
5.1 Maven 集成(pom.xml)
Maven 是 Java 生态中最主流的构建工具,maven-checkstyle-plugin 是 Checkstyle 最推荐的集成方式。
<properties>
<checkstyle.version>13.5.0</checkstyle.version>
<maven-checkstyle-plugin.version>3.6.0</maven-checkstyle-plugin.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${maven-checkstyle-plugin.version}</version>
<dependencies>
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>${checkstyle.version}</version>
</dependency>
</dependencies>
<configuration>
<!-- 指定配置文件路径 -->
<configLocation>config/checkstyle/checkstyle.xml</configLocation>
<!-- 抑制规则文件路径 -->
<suppressionsLocation>config/checkstyle/checkstyle-suppressions.xml</suppressionsLocation>
<!-- 字符编码 -->
<encoding>UTF-8</encoding>
<!-- 控制台输出检查结果 -->
<consoleOutput>true</consoleOutput>
<!-- 发现违规时是否使构建失败 -->
<failsOnError>true</failsOnError>
<!-- 是否包含测试源码目录 -->
<includeTestSourceDirectory>true</includeTestSourceDirectory>
</configuration>
<executions>
<execution>
<id>checkstyle-validation</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
执行命令:
# 执行 Checkstyle 检查
mvn checkstyle:check
# 生成 HTML 报告
mvn checkstyle:checkstyle
# 报告位于 target/site/checkstyle.html
Maven Checkstyle Plugin 文档:https://maven.apache.org/plugins/maven-checkstyle-plugin/
增量检查:在 Maven 中通过 includes / excludes 参数限定检查范围:
<configuration>
<configLocation>config/checkstyle/checkstyle.xml</configLocation>
<!-- 只检查主源码目录 -->
<includeTestSourceDirectory>false</includeTestSourceDirectory>
<!-- 指定包含的源码目录 -->
<sourceDirectories>
<sourceDirectory>${project.build.sourceDirectory}</sourceDirectory>
</sourceDirectories>
<!-- 排除生成的代码 -->
<excludes>**/generated/**,**/target/**</excludes>
</configuration>
5.2 pre-commit 集成(通过 local hook)
Java 项目可通过 repo: local + language: system 将 Checkstyle 集成为 pre-commit local hook。这样 pre-commit run --all-files 一条命令即可在本地提交前和 CI 中执行相同的检查,保证本地与 CI 门禁一致性。
Maven 项目示例:
# .pre-commit-config.yaml
- repo: local
hooks:
- id: checkstyle-check
name: Checkstyle check
entry: mvn checkstyle:check
language: system
files: \.java$
pass_filenames: false
Gradle 项目将 entry 替换为 ./gradlew checkstyleCheck:
- repo: local
hooks:
- id: checkstyle-check
name: Checkstyle check
entry: ./gradlew checkstyleCheck
language: system
files: \.java$
pass_filenames: false
适用前提:本机需安装 JDK 和 Maven(Maven 项目)或 Gradle(Gradle 项目)。
language: system表示直接在本地环境执行命令,不依赖 pre-commit 的 Python 环境。关于
pass_filenames: false:Checkstyle 通过构建配置(pom.xml/build.gradle)和checkstyle.xml配置文件自行确定检查范围,不需要 pre-commit 传入暂存区文件列表,因此关闭文件名传递,让 Maven/Gradle 自行管理检查范围。本地与 CI 一致性:此方式确保本地提交前执行的检查命令与 CI 中执行的
mvn checkstyle:check/./gradlew checkstyleCheck完全一致,避免"本地通过但 CI 失败"的问题。
增量检查:pre-commit 框架默认只将暂存区中变更的 .java 文件传给 hook。但由于 Checkstyle 的 local hook 使用 pass_filenames: false(让 Maven 自行管理检查范围),Maven 的 checkstyle:check 会对整个项目的 **/*.java 执行全量检查,pre-commit 的文件列表不会被传递给 Maven。
为何不能用
pass_filenames: true+-Dcheckstyle.includes实现增量:Maven Checkstyle Plugin 的includes参数类型为String,接受的是 Ant 模式(如**/Foo.java),不是文件路径列表 $TRAE_REF。pre-commit 的pass_filenames: true会将暂存区文件路径以空格分隔追加到entry命令末尾,但这无法作为 Maven 的-Dcheckstyle.includes参数值使用——Maven 期望的是逗号分隔的 Ant 模式,且pass_filenames不支持参数格式转换。因此pass_filenames: true方案不可行。
可行的方案:
-
保持
pass_filenames: false,接受全量检查:Maven 的checkstyle:check全量检查整个项目源码。对于中小型项目,全量 Checkstyle 检查耗时可控(通常数秒),可直接作为 pre-commit hook 使用。Maven 的cacheFile参数可加速重复检查。 -
Git diff + Checkstyle CLI 直调:绕过 Maven 插件,用 Git diff 获取变更文件后直接调用 Checkstyle CLI:
- repo: local
hooks:
- id: checkstyle-incremental
name: Checkstyle (changed files only)
entry: bash -c 'files=$(git diff --name-only --diff-filter=ACMR --cached -- "*.java") && [ -n "$files" ] && java -jar checkstyle-10.21.4-all.jar -c checkstyle.xml $files || true'
language: system
files: \.java$
pass_filenames: false
此方案需要本地安装 Checkstyle CLI(
checkstyle-10.21.4-all.jar),且不经过 Maven 的配置管理(pom.xml中的configLocation、suppressionsLocation等需手动指定)。适合需要严格文件级增量的场景。
- CI 中使用
--from-ref/--to-ref:pre-commit 支持 PR 级增量触发,但由于pass_filenames: false,实际仍由 Maven 全量执行:
# CI 中只在有 .java 文件变更时触发,但 Maven 仍全量检查
pre-commit run checkstyle-check --from-ref origin/main --to-ref HEAD
综合建议:中小型项目直接使用方案 1(全量检查 +
cacheFile加速);大型项目如需严格文件级增量,使用方案 2(Checkstyle CLI 直调),或改用 Spotless 的ratchetFrom实现 Git 级增量。
5.3 IDE 集成
VS Code
安装 Checkstyle for Java 扩展(由 Red Hat 提供),在项目根目录创建 .vscode/settings.json:
{
"java.checkstyle.configuration": "config/checkstyle/checkstyle.xml",
"java.checkstyle.properties": {}
}
说明:VS Code 的 Checkstyle 集成主要通过 Java 扩展包实现,支持实时高亮显示违规。
IntelliJ IDEA
- 安装插件:
Settings>Plugins> 搜索 "Checkstyle-IDEA" 并安装 - 配置插件:
Settings>Tools>Checkstyle- 点击
+添加配置文件,选择config/checkstyle/checkstyle.xml - 勾选
Scan sources和Scan tests - 勾选
Suppress errors可将违规显示为警告而非错误
- 点击
- 实时检查:保存文件时自动执行检查,违规代码会在编辑器中高亮显示
插件仓库:https://plugins.jetbrains.com/plugin/1065-checkstyle-idea
Neovim
通过 nvim-lint 插件集成 Checkstyle,提供异步代码检查能力。
5.4 命令行使用方式
# 基本语法
java -jar checkstyle-13.5.0-all.jar -c /path/to/config.xml /path/to/source/code
# 使用 Google Checks 配置检查指定目录
java -jar checkstyle-13.5.0-all.jar -c /google_checks.xml ./src/main/java
# 检查单个文件
java -jar checkstyle-13.5.0-all.jar -c config.xml src/main/java/com/example/MyClass.java
# 生成 XML 格式报告
java -jar checkstyle-13.5.0-all.jar -c config.xml -f xml -o report.xml ./src
# 生成 SARIF 格式报告
java -jar checkstyle-13.5.0-all.jar -c config.xml -f sarif -o report.sarif ./src
# 指定排除的文件/目录
java -jar checkstyle-13.5.0-all.jar -c config.xml -e target/ -e generated/ ./src
# 使用正则表达式排除文件
java -jar checkstyle-13.5.0-all.jar -c config.xml -x ".*[\\/]generated[\\/].*" ./src
下载地址:从 GitHub Releases 下载最新的
checkstyle-X.X.X-all.jar。
增量检查 -- 通过分析 Git Diff 获取变更的 Java 文件列表,仅对这些文件执行 Checkstyle 检查:
#!/bin/bash
# 获取相对于 main 分支变更的 Java 文件
PREVIOUS=$(git merge-base origin/main HEAD)
FILES=$(git diff --name-only --diff-filter=ACMR $PREVIOUS HEAD | grep '\.java$')
if [ -n "$FILES" ]; then
echo "Checking changed files:"
echo "$FILES"
java -jar checkstyle-13.5.0-all.jar -c config/checkstyle.xml $FILES
if [ $? -ne 0 ]; then
echo "Checkstyle check failed!"
exit 1
fi
else
echo "No Java files changed, skipping Checkstyle."
fi
CI 脚本调用:
GitHub Actions
name: CI Checkstyle
on: [push, pull_request]
jobs:
checkstyle:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: "21"
distribution: "temurin"
- name: Cache Maven dependencies
uses: actions/cache@v4
with:
path: ~/.m2
key: maven-${{ hashFiles('**/pom.xml') }}
restore-keys: maven-
- name: Run Checkstyle
run: mvn checkstyle:check
GitLab CI
checkstyle:
stage: test
image: maven:3.9-eclipse-temurin-21
script:
- mvn checkstyle:check
artifacts:
reports:
checkstyle:
- target/checkstyle-result.xml
增量检查 -- 按 PR/MR 变更文件触发增量扫描:
GitHub Actions 中的增量检查
name: Incremental Checkstyle
on: [pull_request]
jobs:
checkstyle:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: "21"
distribution: "temurin"
- name: Run Checkstyle on Changed Files
run: |
PREVIOUS=$(git merge-base origin/main ${{ github.sha }})
FILES=$(git diff --name-only --diff-filter=ACMR $PREVIOUS ${{ github.sha }} | grep '\.java$')
if [ -n "$FILES" ]; then
echo "Checking files: $FILES"
java -jar checkstyle-13.5.0-all.jar -c config/checkstyle.xml $FILES
else
echo "No Java files changed."
fi
GitLab CI 中的增量检查
checkstyle-incremental:
stage: test
image: maven:3.9-eclipse-temurin-21
script:
- |
FILES=$(git diff --name-only --diff-filter=ACMR $CI_MERGE_REQUEST_DIFF_BASE_SHA $CI_COMMIT_SHA | grep '\.java$')
if [ -n "$FILES" ]; then
echo "Checking files: $FILES"
java -jar checkstyle-13.5.0-all.jar -c config/checkstyle.xml $FILES
else
echo "No Java files changed."
fi
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
5.5 Gradle 集成(build.gradle)
Gradle 内置了 Checkstyle 插件,开箱即用:
plugins {
id 'checkstyle'
}
checkstyle {
toolVersion = '13.5.0'
configFile = file('config/checkstyle/checkstyle.xml')
configProperties = [
'suppressionFile': file('config/checkstyle/checkstyle-suppressions.xml').absolutePath,
'config_loc': file('config/checkstyle').absolutePath
]
}
// 可选:自定义检查任务
tasks.withType(Checkstyle).configureEach {
maxWarnings = 0 // 警告数上限,0 表示不允许任何警告
ignoreFailures = false // 是否忽略失败
}
执行命令:
# 检查主源码
./gradlew checkstyleMain
# 检查测试源码
./gradlew checkstyleTest
# 检查所有源码
./gradlew checkstyle
Gradle Checkstyle Plugin 文档:https://docs.gradle.org/current/userguide/checkstyle_plugin.html
6. 告警抑制(屏蔽)方法
Checkstyle 提供了多种灵活的告警抑制方式,从代码级注释到外部配置文件,满足不同场景的需求。官方过滤器文档:https://checkstyle.org/config_filters.html
6.1 通过集成调度工具屏蔽
Maven excludes 参数
通过 maven-checkstyle-plugin 的 excludes 配置排除特定文件或目录:
<configuration>
<excludes>**/generated/**,**/model/**,**/target/**</excludes>
</configuration>
Gradle exclude 配置
checkstyle {
exclude = ['**/generated/**', '**/model/**']
}
6.2 通过工具配置文件屏蔽
SuppressionFilter(外部 XML 文件)
通过外部 XML 文件定义抑制规则,适合对整个文件、特定类或方法进行批量抑制,是最推荐的企业级抑制方式。
官方文档:https://checkstyle.org/config_filters.html#SuppressionFilter
配置方式:
<module name="Checker">
<module name="SuppressionFilter">
<property name="file" value="${config_loc}/checkstyle-suppressions.xml"/>
<property name="optional" value="true"/>
</module>
</module>
checkstyle-suppressions.xml 示例:
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions>
<!-- 按文件路径抑制 -->
<suppress files=".*[\\/]generated[\\/].*" checks=".*"/>
<suppress files=".*[\\/]model[\\/].*" checks="MagicNumber"/>
<!-- 按检查规则抑制特定文件 -->
<suppress files=".*[\\/]config[\\/].*" checks="JavadocMethod"/>
<suppress files=".*[\\/]config[\\/].*" checks="JavadocType"/>
<!-- 按类名抑制 -->
<suppress checks="LineLength" files="Application\.java"/>
<!-- 按消息内容抑制 -->
<suppress checks="Regexp" message="System\.out\.println"/>
</suppressions>
SuppressionSingleFilter(配置文件内联)
直接在配置文件中内联定义单条抑制规则,无需额外的 XML 文件。
官方文档:https://checkstyle.org/config_filters.html#SuppressionSingleFilter
<module name="Checker">
<module name="SuppressionSingleFilter">
<property name="checks" value="JavadocMethod"/>
<property name="files" value=".*Test\.java"/>
</module>
</module>
6.3 通过工具命令行参数屏蔽
通过命令行的 -e(排除路径)和 -x(排除正则表达式)参数屏蔽特定文件或目录:
官方文档:https://checkstyle.org/cmdline.html#Excluding_Specific_Files_or_Directories
# 排除特定目录
java -jar checkstyle-13.5.0-all.jar -c config.xml -e target/ -e generated/ ./src
# 使用正则表达式排除
java -jar checkstyle-13.5.0-all.jar -c config.xml -x ".*[\\/]generated[\\/].*" ./src
6.4 通过代码屏蔽
@SuppressWarnings 注解(类/方法级)
通过 Java 标准注解 @SuppressWarnings 抑制特定规则的告警。需要在配置中启用 SuppressWarningsFilter。
官方文档:https://checkstyle.org/config_filters.html#SuppressWarningsFilter
配置方式:
<module name="Checker">
<module name="SuppressWarningsFilter"/>
<module name="TreeWalker">
<!-- 其他检查规则 -->
</module>
</module>
使用方式:
@SuppressWarnings("checkstyle:MagicNumber")
public void calculate() {
int timeout = 5000; // 抑制魔法数字检查
}
@SuppressWarnings("checkstyle:HiddenField")
public void setName(String name) { // 抑制参数名与字段名相同检查
this.name = name;
}
SuppressionCommentFilter(代码块级注释)
通过成对的注释(OFF/ON)来抑制一段代码区域内的所有或特定告警。
官方文档:https://checkstyle.org/config_filters.html#SuppressionCommentFilter
配置方式:
<module name="TreeWalker">
<module name="SuppressionCommentFilter">
<property name="offCommentFormat" value="CHECKSTYLE:OFF"/>
<property name="onCommentFormat" value="CHECKSTYLE:ON"/>
</module>
</module>
使用方式:
// CHECKSTYLE:OFF
public void legacyMethod() {
System.out.println("legacy code"); // 不会触发任何告警
int x = 42;
}
// CHECKSTYLE:ON
SuppressWithNearbyCommentFilter(行级注释)
通过在代码行附近添加特定格式的注释来抑制告警,是最常用的代码级抑制方式。
官方文档:https://checkstyle.org/config_filters.html#SuppressWithNearbyCommentFilter
配置方式:
<module name="TreeWalker">
<module name="SuppressWithNearbyCommentFilter">
<property name="commentFormat" value="CHECKSTYLE OFF (\w+) FOR (\d+) LINES"/>
<property name="checkFormat" value="$1"/>
<property name="influenceFormat" value="$2"/>
</module>
</module>
使用方式:
// CHECKSTYLE OFF MagicNumber FOR 3 LINES
int timeout = 5000;
int retryCount = 3;
long interval = 1000L;
// CHECKSTYLE ON
SuppressWithPlainTextCommentFilter(纯文本注释)
使用纯文本格式注释来抑制 Checker 级别的告警(如 RegexpSingleline),适用于 TreeWalker 之外的检查。
官方文档:https://checkstyle.org/config_filters.html#SuppressWithPlainTextCommentFilter
6.5 高级抑制方式
SuppressionXpathFilter(XPath 精确抑制)
基于 XPath 表达式进行精确抑制,可以针对特定的 AST 节点进行细粒度控制。
官方文档:https://checkstyle.org/config_filters.html#SuppressionXpathFilter
<module name="Checker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config_loc}/checkstyle-xpath-suppressions.xml"/>
<property name="optional" value="true"/>
</module>
</module>
6.6 抑制方式对比总结
| 抑制方式 | 粒度 | 配置位置 | 推荐场景 |
|---|---|---|---|
| Maven/Gradle excludes | 文件/目录 | 构建配置 | 排除生成代码、第三方代码 |
命令行 -e / -x |
文件/目录 | CLI 参数 | 临时排除特定路径 |
SuppressionFilter |
文件/类/方法 | 外部 XML 文件 | 企业级批量抑制,推荐使用 |
SuppressionSingleFilter |
文件/类/方法 | 配置文件内联 | 简单场景,无需额外文件 |
@SuppressWarnings |
单个类/方法 | Java 代码中 | 临时抑制特定规则 |
SuppressionCommentFilter |
代码块(OFF/ON) | Java 代码注释中 | 抑制遗留代码块 |
SuppressWithNearbyCommentFilter |
指定行数范围 | Java 代码注释中 | 抑制少量代码行的特定规则 |
SuppressionXpathFilter |
AST 节点级 | 外部 XML 文件 | 精确到特定代码结构 |