本文探讨了 Java Diff Utils 及其各种功能。Java Diff Utils 提供了一个灵活的开源解决方案,用于比较 Java 应用程序中的文本数据。从基本的逐行差异比较到完整的统一差异生成和修补功能,它是构建强大的版本控制或变更跟踪系统的基础工具。
Java Diff Utils 具有最少的设置和高度可读的输出,对于使用版本化数据、协作编辑工具或文件监控系统的开发人员来说,它是必备的。
在现代软件开发中,跟踪和可视化不同版本文件或内容之间的变化至关重要。无论我们构建的是版本控制系统、协作编辑器还是代码审查工具,高效地比较内容都至关重要。在 Java 中,实现此目的的一种流行方法是使用Java Diff Utils。
本教程演示了如何使用 Java Diff Utils 库执行各种任务,包括逐行比较文本内容、生成统一差异、应用补丁以恢复或修改内容以及构建并排差异视图。
了解 Java Diff 实用程序及其主要优点
Java Diff Utils 是一个轻量级且功能强大的库,用于计算文本数据之间的差异。它支持字符级和行级比较,并生成统一的差异输出。
它通常用于版本控制系统,并应用补丁将一个版本的数据转换为另一个版本。此实用程序提供了各种类和方法来简化比较过程。
以下是 Java Diff Utils 的主要优点:
- 简单:提供简洁直观的 API 和静态实用方法
- 可扩展性:轻松与 Spring Boot 服务和控制器集成
- 跨平台:兼容任何支持 Java 的操作系统
- 开源:根据 Apache 许可自由使用和修改
这些功能使 Java Diff Utils 成为 Java 应用程序中可靠文本比较功能的理想选择。设置 Diff Utils
在深入研究之前,我们将通过Spring Initializr使用 Maven设置一个简单的Spring Boot应用程序。
虽然 Java Diff Utils 可以在纯 Java 中使用,只需手动管理 JAR 文件和类路径即可,但 Spring Boot 和 Maven 可以通过pom.xml自动处理所有依赖项,从而简化了这一过程。这种方法不仅减少了设置时间,还确保了跨环境的更好的可移植性和一致性。Maven 负责下载、管理和解析所有必需的构件。
首先,我们将Java Diff Utils 依赖项添加到我们的pom.xml文件中:
<dependency> <groupId>io.github.java-diff-utils</groupId> <artifactId>java-diff-utils</artifactId> <version>4.12</version> </dependency>
|
通过此设置,Maven 可确保在编译和运行时均可使用正确版本的 Java Diff Utils。现在,我们可以直接使用DiffUtils、Patch和UnifiedDiffUtils等核心类了 。这些类都是基于实用程序的,这意味着无需显式创建实例。这种设计允许直接集成到服务类、控制器层或独立的 Java 组件中。
在 Java 中使用 Diff 实用程序
在本节中,我们将逐步构建一些基本组件,以学习如何在各种场景中使用 Java Diff Utils 库。我们将探讨几个核心用例,并研究在 Java 应用程序中使用各种策略比较文本内容的实现。我们将使用 Java Diff Utils 库创建用于比较内容、生成 diff、应用补丁以及并排查看更改的实现。
让我们进一步探讨其核心用例和实现。
比较字符串列表
让我们创建一个名为TextComparatorUtil的工具类,用于比较两个字符串列表,并生成一个表示它们差异的补丁。这个工具类简化了识别文本版本之间差异的过程:
class TextComparatorUtil { public static Patch<String> compare(List<String> original, List<String> revised) { return DiffUtils.diff(original, revised); } }
|
让我们验证TextComparatorUtil是否正确检测并报告两个字符串列表之间的变化:@Test void givenDifferentLines_whenCompared_thenDetectsChanges() { var original = List.of("A", "B", "C"); var revised = List.of("A", "B", "D"); var patch = TextComparatorUtil.compare(original, revised); assertEquals(1, patch.getDeltas().size()); assertEquals("C", patch.getDeltas().get(0).getSource().getLines().get(0)); assertEquals("D", patch.getDeltas().get(0).getTarget().getLines().get(0)); }
|
生成统一的差异
接下来,让我们创建一个类UnifiedDiffGeneratorUtil,它在两个字符串列表之间生成统一的差异,以标准补丁格式表示差异:
class UnifiedDiffGeneratorUtil { public static List<String> generate(List<String> original, List<String> revised, String fileName) { var patch = DiffUtils.diff(original, revised); return UnifiedDiffUtils.generateUnifiedDiff(fileName, fileName + ".new", original, patch, 3); } }
|
当我们指定原始内容和修订内容以及文件名时,它会生成适合代码审查或版本控制系统的统一差异输出。让我们编写一个 Junit 测试来确保UnifiedDiffGeneratorUtil在统一差异输出中正确突出显示修改过的行:
@Test void givenModifiedText_whenUnifiedDiffGenerated_thenContainsExpectedChanges() { var original = List.of("x", "y", "z"); var revised = List.of("x", "y-modified", "z"); var diff = UnifiedDiffGeneratorUtil.generate(original, revised, "test.txt"); assertTrue(diff.stream().anyMatch(line -> line.contains("-y"))); assertTrue(diff.stream().anyMatch(line -> line.contains("+y-modified"))); }
|
应用补丁
接下来,我们编写一个PatchUtil类,生成并应用补丁来更新原始内容。它将原始字符串列表转换为修订版本:
class PatchUtil { public static List<String> apply(List<String> original, List<String> revised) throws PatchFailedException { var patch = DiffUtils.diff(original, revised); return DiffUtils.patch(original, patch); } }
|
它首先计算差异,然后应用生成的补丁来更新原始内容。现在,我们将验证PatchUtil是否正确应用了补丁,以便原始列表与修改后的列表相匹配:
@Test void givenPatch_whenApplied_thenMatchesRevised() throws PatchFailedException { var original = List.of("alpha", "beta", "gamma"); var revised = List.of("alpha", "beta-updated", "gamma"); var result = PatchUtil.apply(original, revised); assertEquals(revised, result); }
|
构建并排差异视图
最后,让我们创建一个 SideBySideViewUtil类,它提供一种方法,以可读的格式显示两个字符串列表之间的差异:
public class SideBySideViewUtil { private static final Logger logger = Logger.getLogger(SideBySideViewUtil.class.getName()); public static void display(List<String> original, List<String> revised) { var patch = DiffUtils.diff(original, revised); patch.getDeltas().forEach(delta -> { logger.log(Level.INFO,"Change: " + delta.getType()); logger.log(Level.INFO,"Original: " + delta.getSource().getLines()); logger.log(Level.INFO,"Revised: " + delta.getTarget().getLines()); }); } }
|
它识别每个更改,并打印更改类型以及原始版本和修订版本中相应的行。这使得更容易快速地可视化和理解文本版本之间的修改。虽然 Java Diff Utils 不会直接生成 HTML 视图,但它会公开来自差异的源代码和目标行。这些可用于构建自定义的可视化表示,然后将其转换为适用于基于 Web 的差异查看器的格式化 HTML。
此测试验证在比较两个不同的字符串列表时,SideBySideViewUtil.display ()方法是否正确执行:
@Test void givenDifferentLists_whenDisplayCalled_thenNoExceptionThrown() { List<String> original = List.of("line1", "line2", "line3"); List<String> revised = List.of("line1", "line2-modified", "line3", "line4"); SideBySideViewUtil.display(original, revised); }
|