312

您使用什么工具在大型 Java 项目中查找未使用/死代码?我们的产品已经开发了几年,手动检测不再使用的代码变得非常困难。但是,我们确实尝试删除尽可能多的未使用代码。

对一般策略/技术(特定工具除外)的建议也值得赞赏。

编辑:请注意,我们已经使用了代码覆盖工具(Clover、IntelliJ),但这些帮助不大。死代码仍然有单元测试,并显示为已覆盖。我想一个理想的工具会识别出几乎没有其他代码依赖于它的代码集群,从而允许手动检查文档。

4

21 回答 21

226

一个运行良好的 Eclipse 插件是Unused Code Detector

它处理整个项目或特定文件,并显示各种未使用/无效的代码方法,以及建议可见性更改(即可以保护或私有的公共方法)。

于 2008-10-02T15:14:09.937 回答
64

CodePro最近由 Google 与 Eclipse 项目一起发布。它是免费且高效的。该插件具有“查找死代码”功能,具有一个/多个入口点。效果很好。

于 2011-03-29T16:34:01.513 回答
42

我会检测正在运行的系统以保留代码使用日志,然后开始检查数月或数年未使用的代码。

例如,如果您对未使用的类感兴趣,则可以检测所有类以在创建实例时进行记录。然后一个小脚本可以将这些日志与完整的类列表进行比较,以找到未使用的类。

当然,如果您进入方法级别,则应牢记性能。例如,这些方法只能记录它们的第一次使用。我不知道如何在 Java 中最好地做到这一点。我们在 Smalltalk 中做到了这一点,它是一种动态语言,因此允许在运行时修改代码。我们使用日志调用检测所有方法,并在第一次记录方法后卸载日志代码,因此在一段时间后不会再发生性能损失。也许可以在 Java 中使用静态布尔标志完成类似的事情......

于 2008-10-02T14:48:19.343 回答
32

我很惊讶这里没有提到ProGuard 。它是最成熟的产品之一。

ProGuard是一个免费的 Java 类文件收缩器、优化器、混淆器和预验证器。它检测并删除未使用的类、字段、方法和属性。它优化字节码并删除未使用的指令。它使用简短的无意义名称重命名剩余的类、字段和方法。最后,它会为 Java 6 或 Java Micro Edition 预先验证处理后的代码。

ProGuard 的一些用途是:

  • 创建更紧凑的代码,用于更小的代码存档、更快的网络传输、更快的加载和更小的内存占用。
  • 使程序和库更难逆向工程。
  • 列出死代码,因此可以从源代码中删除。
  • 重新定位和预验证 Java 6 或更高版本的现有类文件,以充分利用其更快的类加载。

这里列出死代码的示例:https ://www.guardsquare.com/en/products/proguard/manual/examples#deadcode

于 2011-08-22T07:40:14.660 回答
25

众所周知,我在 Eclipse 中对单个类所做的一件事是将其所有方法更改为私有方法,然后看看我收到了哪些投诉。对于使用的方法,这将引发错误,我将它们返回到我可以的最低访问级别。对于未使用的方法,这将引发有关未使用方法的警告,然后可以将其删除。作为奖励,您经常会发现一些可以而且应该设为私有的公共方法。

但它非常手动。

于 2009-01-28T19:45:32.723 回答
15

使用测试覆盖工具来检测您的代码库,然后运行应用程序本身,而不是测试。

EmmaEclemma将为您提供关于在任何给定的代码运行中运行的类的百分比的很好的报告。

于 2008-10-02T16:21:17.917 回答
13

我们已经开始使用Find Bugs来帮助识别我们代码库的目标丰富的重构环境中的一些问题。我还会考虑使用Structure 101来识别代码库架构中过于复杂的点,这样你就知道真正的沼泽在哪里。

于 2008-10-02T14:47:49.857 回答
12

理论上,您无法确定性地找到未使用的代码。有一个数学证明(嗯,这是一个更一般定理的特例)。如果您好奇,请查看停机问题。

这可以通过多种方式在 Java 代码中体现出来:

  • 根据用户输入、配置文件、数据库条目等加载类;
  • 加载外部代码;
  • 将对象树传递给第三方库;
  • 等等

话虽如此,我使用 IDEA IntelliJ 作为我选择的 IDE,它具有广泛的分析工具,用于查找模块、未使用的方法、未使用的成员、未使用的类等之间的依赖关系。它也非常智能,就像一个不被调用的私有方法是标记为未使用但公共方法需要更广泛的分析。

于 2008-10-02T14:28:07.627 回答
8

在 Eclipse 中转到 Windows > Preferences > Java > Compiler > Errors/Warnings
并将它们全部更改为错误。修复所有错误。这是最简单的方法。美妙之处在于,这将允许您在编写代码时清理代码。

截图 Eclipse 代码:

在此处输入图像描述

于 2016-01-21T10:51:55.773 回答
5

IntelliJ 具有用于检测未使用代码的代码分析工具。您应该尝试使尽可能多的字段/方法/类尽可能不公开,这将显示更多未使用的方法/字段/类

我也会尝试定位重复代码以减少代码量。

我的最后一个建议是尝试找到开源代码,如果使用它会使您的代码更简单。

于 2009-02-23T20:31:11.320 回答
5

Structure101切片透视图将给出与“主”集群没有依赖关系的类或包的任何“孤儿”或“孤儿组”的列表(和依赖图)。

于 2009-11-17T13:40:44.653 回答
3

DCD 不是某些 IDE 的插件,但可以从 ant 或独立运行。它看起来像一个静态工具,它可以做 PMD 和 FindBugs 做不到的事情。我会试试。

PS 正如下面评论中提到的,该项目现在位于GitHub中。

于 2012-06-28T08:29:52.990 回答
2

有一些工具可以分析代码并提供代码覆盖率数据。这使您可以看到(在运行代码时)调用了多少。您可以获得这些工具中的任何一个来找出您拥有多少孤儿代码。

于 2008-10-02T14:24:38.120 回答
2
  • FindBugs 非常适合这类事情。
  • PMD(Project Mess Detector)是另一个可以使用的工具。

但是,两者都找不到工作区中未使用的公共静态方法。如果有人知道这样的工具,请告诉我。

于 2009-01-28T19:38:13.643 回答
1

用户覆盖工具,例如 EMMA。但它不是静态工具(即它需要通过回归测试和所有可能的错误情况来实际运行应用程序,这是不可能的:))

尽管如此,EMMA 还是非常有用的。

于 2008-10-02T16:16:09.617 回答
1

代码覆盖工具,例如 Emma、Cobertura 和 Clover,将检测您的代码并通过运行一组测试记录它的哪些部分被调用。这非常有用,应该是您开发过程中不可或缺的一部分。它将帮助您确定测试套件对代码的覆盖程度。

但是,这与识别真正的死代码不同。它仅标识测试覆盖(或未覆盖)的代码。这可能会给您带来误报(如果您的测试未涵盖所有场景)以及误报(如果您的测试访问实际上从未在现实世界场景中使用过的代码)。

我想真正识别死代码的最佳方法是在实时运行环境中使用覆盖工具检测您的代码,并在较长时间内分析代码覆盖率。

如果您在负载均衡的冗余环境中运行(如果不是,为什么不呢?),那么我认为只检测您的应用程序的一个实例并配置您的负载均衡器以便随机但很小的一部分是有意义的您的用户在您的检测实例上运行。如果您在很长一段时间内执行此操作(以确保您已涵盖所有现实世界的使用场景 - 例如季节性变化),您应该能够准确地看到您的代码的哪些区域在现实世界使用中被访问以及哪些部分真的从来没有被访问过,因此是死代码。

我从未亲眼见过这样做,也不知道如何使用上述工具来检测和分析未通过测试套件调用的代码 - 但我相信它们可以。

于 2008-11-26T16:40:09.520 回答
1

有一个 Java 项目 -死代码检测器(DCD)。对于源代码,它似乎不能很好地工作,但对于 .jar 文件 - 它真的很好。另外,您可以按类和方法过滤。

于 2013-09-06T12:55:54.930 回答
1

这里的Netbeans是 Netbeans死码检测器 的插件。

如果它可以链接并突出显示未使用的代码会更好。您可以在这里投票和评论:Bug 181458 - 查找未使用的公共类、方法、字段

于 2017-02-12T04:39:59.593 回答
0

Eclipse 可以显示/突出显示无法访问的代码。JUnit 可以向您显示代码覆盖率,但您需要进行一些测试,并且必须确定相关测试是否缺失或代码是否真的未使用。

于 2008-10-02T14:24:28.697 回答
0

我找到了 Clover 覆盖工具,它检测代码并突出显示已使用和未使用的代码。与 Google CodePro Analytics 不同,它也适用于 WebApplications(根据我的经验,我对 Google CodePro 的看法可能不正确)。

我注意到的唯一缺点是它没有考虑 Java 接口。

于 2011-12-13T10:14:00.663 回答
0

我使用 Doxygen 开发了一个方法调用映射来定位从未调用过的方法。在图表上,您会发现没有调用者的方法集群孤岛。这不适用于库,因为您需要始终从某个主要入口点开始。

于 2017-03-01T21:22:12.897 回答