Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Don’t delete Java code just because an IDE marks it unused, tests never reach it, or a short production sample fails to show it. Treat each signal as a lead, combine static, test, and runtime evidence, then review and retire candidates in controlled steps.

What counts as dead Java code—and what does not?

Dead code is code that an application no longer needs or executes in its relevant operating context. In practice, “looks unused” is a safer starting label than “dead”: a static inspection, a test run, and production observation answer different questions.

  • Static inspection can identify declarations that appear unreachable from configured entry points or are otherwise suspicious. It cannot by itself establish whether production uses them.
  • Test coverage records what ran during a particular test run. A line not covered by those tests may still be used in production; coverage also does not distinguish test-only calls from production business traffic.
  • Runtime inventory records code observed under the workloads and time period included in its configuration. Absence from a report means “not observed in this scope,” not “safe to delete.”

There is no universal, established percentage of application code that is dead. A figure sometimes cited for code that developers did not understand or document is not a measured dead-code rate and should not be used as one.

Compare the evidence before deciding

Approach What it can show Main limitation Best use
IDE or static inspection Declarations that appear unreachable from configured entry points, unused locals, and other suspicious code. Project configuration and recognized entry points matter. Static references do not prove production use, and some editor highlighting is intentionally limited. A low-cost first pass and routine developer feedback.
Test coverage Lines and branches executed during a particular test run. IntelliJ IDEA can consume JaCoCo coverage reports. It describes the selected tests, not all production behavior. Untested code is not necessarily unused. Improving test visibility and locating areas that tests do not exercise.
Production runtime inventory Code observed in the configured production environments over the observation period. Unobserved code may belong to rare, dormant, seasonal, or unrepresented flows. Scope, setup, and service requirements apply. Prioritizing review in larger Java estates where production evidence can materially inform decisions.

Build a review process before removing candidates

1. Set the scope and make an inventory

Start by deciding whether the cleanup covers first-party Java code, third-party dependencies, or both. These are different problems: code-level analysis helps identify suspicious declarations, while dependency review asks whether the application still needs a library and whether its version poses maintenance or security concerns. Record the repositories, services, owners, and relevant build configurations in scope.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Agree on a team definition of a candidate, what evidence reviewers expect, who owns approval, and how the change will be tested and rolled back. An inventory with an owner and a status is more useful than a one-time list of warnings.

2. Gather several kinds of evidence

Use static analysis to find candidates, then compare those findings with representative test coverage and, where it is justified and available, runtime observations from real production workloads. Treat each source according to what it measures rather than combining them into a false yes-or-no verdict.

Coverage tools such as IntelliJ IDEA can help explain what a test run executed, and JetBrains documents Java coverage and inspection behavior in its code coverage documentation and unused-symbol inspection documentation. JetBrains notes that inspections use configured entry points; some in-editor highlighting may not show every finding.

For production observations, consider the scope and duration carefully. A short or unrepresentative window can miss batch jobs, seasonal tasks, infrequent customer actions, or dormant integrations. Azul recommends production observation because it reflects business load, but that recommendation is a vendor’s guidance, not proof that any particular observation period is sufficient.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

3. Check paths tools may not reveal

Before labeling a candidate dead, ask application owners to inspect likely indirect or infrequent paths. In particular, check:

  • Reflection, dependency injection, and framework-discovered components.
  • Configuration-driven behavior, plugin mechanisms, and externally invoked entry points.
  • Scheduled jobs, batch processing, maintenance tasks, and seasonal workflows.
  • Integrations or customer paths that were not represented in the test suite or observation window.
  • References from other modules, services, scripts, or deployment configurations within the agreed scope.

These checks matter because static analysis depends on recognized entry points, while runtime tools only report activity actually observed within their configured scope.

4. Deprecate, monitor, then remove

A staged approach reduces the risk of turning an uncertain finding into an outage. Azul documents a workflow that identifies candidates, deprecates them, monitors for use, and later marks and removes code. Treat this as Azul’s recommended process, not a universally validated standard.

  1. Identify: Record the candidate, its owner, the evidence, and the scope and dates of any runtime observations.
  2. Review: Ask maintainers to check direct and indirect callers, configuration, and operational paths. Resolve evidence conflicts rather than choosing the most convenient signal.
  3. Deprecate: Where appropriate, mark the API or component as deprecated and communicate the change to its known consumers.
  4. Monitor: Watch for observed use, failures, or consumer reports over a period that covers the relevant workload. A quiet interval alone is not proof of non-use.
  5. Remove incrementally: Make small changes through normal builds, tests, and deployment controls. Keep a practical rollback path and update the inventory with the outcome.

Azul says OpenRewrite can be used to automate adding deprecation annotations based on Code Inventory report data. That is a vendor-described option; verify that the automation fits your codebase and review its changes rather than assuming it is a tested fit for every project.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

When a production code inventory helps

For a large estate or an application with difficult-to-reproduce workloads, production observations can add evidence that static analysis and tests cannot provide. Azul Intelligence Cloud Code Inventory is one vendor-documented service for reporting observed code use. Azul says its default reporting is at class level and that method-level detail requires additional arguments; it describes access to reports through an API or web UI.

Azul’s setup documentation makes an important scope distinction: “Code Inventory tracks first method invocation – it does not reproduce the entire inventory of available code found within source files and bytecode.” That means the report is evidence of observed invocation, not a complete catalog of everything present or a standalone deletion authorization. The service’s setup and reporting scope should be evaluated against your application and operational requirements.

Measure outcomes locally

Track results that matter to your team: candidate review time, code and dependencies removed, findings that required investigation, build and test duration, and delivery cadence. This helps determine whether the cleanup is reducing maintenance burden without substituting a borrowed success story for your own results.

Computer Weekly reported a Goldman Sachs example in 2024, attributing to core engineering VP Darshan Mehta a 67% reduction in codebase size and a pace of more than 250 releases per year. That is a reported company-specific case, not a benchmark or promised result for other teams. The same article reported Veracode figures, via Eric Costlow, of 38,278 unique applications running Log4j versions 1.1 through 3.0.0-alpha1 across 3,866 organizations. Those figures illustrate a reported dependency-maintenance concern; they do not measure dead code in Java applications.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

In that May 29, 2024 Computer Weekly article, Azul’s Eric Costlow summarized his advice as “track what runs and focus on that.” Use runtime evidence to focus review, not to automate deletion. Because Costlow was identified as Azul’s senior director of product management, readers should understand that this is vendor-affiliated advice; the specific service capabilities above are likewise Azul’s own descriptions.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.