You are about to merge a pull request that compiles cleanly, passes every unit test, and still ships a null-pointer dereference that only crashes in production under load. Java’s three veteran analysis tools exist precisely to catch what compilation and tests miss — but teams routinely bolt all three onto CI without understanding that Checkstyle (9,558 stars) reads your source code’s style, PMD (5,485 stars) reads your source code’s logic, and SpotBugs (3,935 stars) reads your compiled bytecode. They are not redundant; they are three different layers of the same review. As of this week all three projects pushed updates — Checkstyle 14.1.0, SpotBugs 4.10.4, and PMD 7.27.0 — making this the right moment to figure out which ones your build actually needs.

TL;DR — Quick Verdict

Adopt Checkstyle first if your team cannot agree on formatting — it is the cheapest tool to satisfy and the only one of the three that makes code reviews about substance instead of tabs. Add PMD second — its 400+ source-level rules catch real language misuse (empty catch blocks, needless object creation, broken equals/hashCode contracts) across Java and 15 other languages, and its CPD engine finds copy-pasted code that refactoring tools miss. Add SpotBugs last, but do not skip it — it is the only one that inspects bytecode, so it finds bugs the others structurally cannot: unsafe publication of internal state, ignored return values, and concurrency mistakes that survive compilation. If you only run one, run PMD; if you want a genuinely hardened build, run all three — they overlap less than 15% in what they flag.

Quick Comparison Table

DimensionCheckstyle 14.1.0PMD 7.27.0SpotBugs 4.10.4
GitHub stars9,5585,4853,935
Last push (2026)Sep 07Sep 07Sep 07
LicenseLGPL-2.1BSD-styleLGPL-2.1
What it analyzesSource code (text/tokens)Source code (AST)Compiled bytecode
Primary purposeCoding conventions & styleLogic flaws, language misuse, duplicatesBug patterns: nulls, concurrency, exposure
Rule count~200 checks400+ rules~450 bug patterns
LanguagesJavaJava + 15 others (Kotlin, Swift, PL/SQL, JS…)Java & JVM bytecode
Duplicate detectionNoYes (CPD)No
Requires compiled classesNoNoYes
Custom rulesXML modules, JavaJava or XPath queriesJava (detector classes)
Best integrationGradle built-in / Maven pluginMaven/Gradle plugin, CLIMaven 4.10.4.1 / Gradle 6.5.11 plugins

Decision Matrix — Pick in 10 Seconds

Use CaseRecommended ToolWhy
Enforce a style guide (imports, Javadoc, line length) in reviewCheckstyleDeterministic, configurable, zero false-positive drama
“The code works but smells” — empty catches, unused locals, broken contractsPMDBest breadth of source-level rules; also detects duplication via CPD
Find bugs that only exist in compiled behavior (state exposure, concurrency)SpotBugsBytecode inspection sees what source tools cannot
Multi-language repo (Java + Kotlin + JavaScript)PMDOnly one of the three that parses non-Java sources
Legacy codebase compiled for Java 8, running on JDK 21SpotBugsAnalyzes old bytecode; needs JDK 11+ to run, not to analyze
One-command CI quality gate for a Maven buildAll three via pluginscheckstyle:check, pmd:check, spotbugs:check compose in one verify phase

Checkstyle — The Style Enforcer That Keeps Reviews Human

Checkstyle is the oldest of the trio (born 2001) and philosophically the simplest: it parses your source into tokens and checks them against a configuration tree. It ships with Google Java Style and Sun Conventions built in, so a team can adopt it with a one-line config decision, then tune from there. Its canonical workflow — a config file, a source file, a violation report — is straight from the project README:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$ cat config.xml
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
          "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
          "https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
  <module name="TreeWalker">
    <module name="FallThrough"/>
  </module>
</module>

$ java -jar checkstyle-14.1.0-all.jar -c config.xml Test.java
Starting audit...
[ERROR] Test.java:9:9: Fall through from previous branch of switch statement [FallThrough]
Audit done.
Checkstyle ends with 1 errors.

That -all.jar artifact is the whole tool in one executable — ideal for pre-commit hooks and local runs that do not want a build system involved. In Gradle, Checkstyle is special: it is a built-in plugin, so no third-party version to track:

1
2
plugins { id 'checkstyle' }
checkstyle { toolVersion = '14.1.0' }   // config/checkstyle/checkstyle.xml is auto-detected

Run gradle check and violations fail the build; run gradle checkstyleMain for a report. The killer feature is not detection power but predictability: Checkstyle either matches your config or it does not, which makes it the only one of the three you can safely run in pre-commit with zero noise. What it will never do is find a logic bug — style checks are a contract with your future self, not a safety net.

PMD — The Broadest Source-Level Net (Plus Duplication Detection)

PMD parses source into an abstract syntax tree with JavaCC and Antlr, then runs rules against that tree — which is why it can find things that have nothing to do with formatting: empty catch blocks, unnecessary object creation, unused variables, and broken equals()/hashCode() pairs. It is also the only member of the trio that speaks 15 other languages (Kotlin, Swift, JavaScript, PL/SQL, and more), making it the default choice for polyglot repositories. Rule count is north of 400, and custom rules are written in Java or as XPath queries over the AST — a genuinely unique capability. The PMD 7 CLI (from the project’s installation docs) is refreshingly direct:

1
2
3
4
$ pmd check -f text -R rulesets/java/quickstart.xml src/main/java
.../src/main/java/com/me/RuleSet.java:123  These nested if statements could be combined
.../src/main/java/com/me/RuleSet.java:231  Useless parentheses.
.../src/main/java/com/me/RuleSetWriter.java:66     Avoid empty catch blocks

PMD 7 also introduced single-rule references by category, so you can stage adoption instead of switching on a 400-rule firehose:

1
$ pmd check -f text -R category/java/codestyle.xml/UnnecessaryModifier src/main/java

The second half of PMD’s value is CPD, the copy-paste detector, which tokenizes source and reports duplicated blocks across 20+ languages:

1
2
3
4
$ pmd cpd --minimum-tokens 100 /home/me/src
Found a 7 line (110 tokens) duplication in the following files:
Starting at line 579 of /home/me/src/test/java/foo/FooTypeTest.java
Starting at line 586 of /home/me/src/test/java/foo/FooTypeTest.java

For Maven projects, mvn pmd:check runs a ruleset against src/main/java and fails the build on violations; mvn pmd:cpd-check does the same for duplication. Because PMD operates on source, it needs no compile step — which makes it the fastest of the three to introduce into an existing repository with thousands of files. If duplication detection across mixed languages is your primary goal, we have a dedicated comparison of duplication detection tools: jscpd, PMD CPD, and duplo.

SpotBugs — The Only One That Reads Bytecode

SpotBugs is the community successor to FindBugs (which stopped development in 2016), and its architecture is fundamentally different: it analyzes compiled .class files, not source. That lets it find bug classes the source-level tools cannot see, because some bugs only exist after compilation — the canonical examples being exposure of internal state (a getter returning the mutable array or Date field it should clone: pattern EI_EXPOSE_REP), ignored return values on immutable objects, and incorrect lazy-initialization in multi-threaded code. It requires JDK 11+ to run, but it analyzes code compiled for older JVMs — the README is explicit that it handles “code compiled with older versions” — which makes it the tool of choice for legacy jar triage.

The Gradle plugin (current version 6.5.11) wires into the check lifecycle:

1
2
3
4
5
6
7
8
plugins {
  id 'java'
  id 'com.github.spotbugs' version '6.5.11'
}
spotbugs {
  effort = 'max'        // Min / Default / Max analysis depth
  reportLevel = 'low'   // High / Medium / Low confidence threshold
}

Maven users get the same via the com.github.spotbugs:spotbugs-maven-plugin (4.10.4.1) with a check goal that fails the build, plus spotbugs:spotbugs for the report. The trade-off to know up front: because SpotBugs needs compiled classes, it belongs after compile in your pipeline, and its findings need an auxiliary classpath of your dependencies to avoid false positives on types it cannot resolve. Teams that skip the auxclasspath configuration are the ones who declare SpotBugs “too noisy” — usually after drowning in EI_EXPOSE_REP reports that a properly configured analysis classpath cuts by half.

Pitfalls — What the Tutorials Do Not Tell You

Generated code will poison all three tools. Lombok-generated getters, builders, and equals() implementations confuse PMD and Checkstyle (they see fields without the accessors that use them) and can produce phantom violations. Options: run analysis on delomboked sources, or configure suppression by path — every tool supports an exclude filter, and you should set it up the day you adopt the tool, not the day the first generated-file violation blocks a release.

Checkstyle and SpotBugs have opposite noise profiles. Checkstyle is deterministic — every finding is “true” by your own config’s definition, so noise is self-inflicted. SpotBugs is heuristic — every finding is a candidate, ranked by confidence, and on a large legacy codebase even reportLevel = 'high' can surface hundreds of issues. Start with High confidence only, triage for two weeks, then lower the bar. PMD sits in between: its best-practices and error-prone rule categories are low-noise, while its design and codestyle categories are subjective — stage those last.

All three in one Maven verify can double your build time. On a large multi-module project, Checkstyle + PMD + SpotBugs serially can add minutes per module. The pragmatic split: Checkstyle in pre-commit (fast, file-scoped), PMD on every PR (mvn pmd:check), SpotBugs on the full build or nightly (mvn spotbugs:check with effort = Max). You lose nothing — SpotBugs at Max effort on a nightly cadence catches what a per-PR Min-effort run would miss anyway.

CPD’s token approach reports duplication, not debt. Two blocks that look identical but differ in one variable name are semantically duplicated yet token-distinct — CPD will miss them, while a refactoring tool or a code review catches them. Treat CPD as a floor, not a ceiling.

Suppression is a code smell — but so is a broken build at 4:59 PM. Every tool lets you suppress inline (// CHECKSTYLE:OFF, @SuppressFBWarnings, // NOPMD). Use them sparingly and require a comment explaining why; an unexplained suppression is how bugs get a permanent alibi.

Static analysis is a per-language sport. Java’s trio has direct counterparts elsewhere: Go teams standardize on golangci-lint, staticcheck, and revive in our Go code quality tools comparison; Swift developers choose between SwiftLint, Periphery, and SwiftFormat; PHP has PHPStan vs Psalm vs PHP-CS-Fixer; and Kotlin’s answer is detekt vs ktlint vs spotless. If you maintain JVM services, our Java web frameworks comparison shows where these quality gates typically get deployed.

FAQ

Can Checkstyle, PMD, and SpotBugs run side by side without duplicate findings? Yes, and this is the recommended setup — they operate on different artifacts (source tokens, source AST, bytecode) so their findings overlap less than 15%. The one genuine overlap is rules like “empty catch block” that exist in both PMD and SpotBugs; if you run both, disable the duplicate category in one of them (typically PMD’s errorprone subset that mirrors SpotBugs patterns) to keep reports readable.

Which tool is best for a legacy codebase with millions of lines of old Java? SpotBugs, because it analyzes compiled bytecode and therefore works on code you may not even have source for — and it can analyze classes compiled for old JVMs even when your toolchain is modern. PMD is the second choice: its rulesets scale to large trees, but expect a large initial backlog that you will want to suppress-by-package while you triage. Checkstyle is least useful here unless you plan to reformat the legacy code.

Do I need all three, or is one enough for a small project? For a small project or library, PMD alone gives the best return: source-level logic rules plus CPD duplication detection in one tool. Add Checkstyle when more than one person commits regularly (it settles style arguments mechanically), and add SpotBugs the moment your code touches concurrency, serialization, or mutable state shared across classes.

How do these tools integrate with modern CI and pre-commit workflows? All three have first-class Maven and Gradle plugins whose check goals fail builds on violations, plus CLI jars that run standalone. Checkstyle is a built-in Gradle plugin (no version to maintain); SpotBugs’ Gradle plugin is com.github.spotbugs (6.5.11 as of this writing); PMD’s Maven plugin binds pmd:check and pmd:cpd-check to the verify phase. All three also publish SARIF or XML reports that GitHub Actions and GitLab CI can render as annotations.

Are these tools still maintained in 2026, or should I migrate to newer alternatives? All three are actively maintained — Checkstyle 14.1.0, PMD 7.27.0, and SpotBugs 4.10.4 were all released within days of this article, and all three repos show commits the same week. Newer JVM analyzers (Error Prone, Semgrep, SonarQube) are complementary, not replacements: Error Prone works as a compiler plugin, Semgrep does pattern matching across languages, and SonarQube aggregates everything — but the three tools in this article remain the standard zero-cost baseline, and SonarQube itself runs Checkstyle, PMD, and SpotBugs rules under the hood.

What is the difference between PMD and CPD? PMD is the analyzer; CPD (Copy-Paste Detector) is a separate utility shipped inside the same distribution. pmd check runs rule sets against source trees, while pmd cpd --minimum-tokens 100 <src> tokenizes files and reports duplicated blocks above a token threshold across 20+ languages including Java, Kotlin, C, and Python.


💰 想测试你的市场判断力?我用 Polymarket 做预测市场交易——这是全球最大的预测市场平台,从大选结果到技术监管时间线,什么都可以押注。和赌博不同,这是真正的信息市场:你懂的信息越多,胜率越高。我靠预测技术相关事件的走向已经赚了不少。用我的邀请链接注册:Polymarket.com