1. 概述

在现代软件开发中,追踪和可视化文件或内容不同版本之间的变更至关重要。无论是构建版本控制系统、协作编辑器还是代码审查工具,高效的内容比较都是核心需求。在 Java 生态中,Java Diff Utils 是实现这一功能的流行方案。

本教程将演示如何使用 Java Diff Utils 库完成多种任务,包括逐行文本比较、生成统一差异格式、应用补丁恢复内容,以及构建并排差异视图。

2. Java Diff Utils 核心优势解析

Java Diff Utils 是一个轻量级且强大的文本差异计算库,支持字符级和行级比较,并能生成标准统一差异输出。它常用于版本控制系统,通过应用补丁将数据从一个版本转换为另一个版本。该库提供了丰富的类和方法简化比较过程。

核心优势总结

  • 简洁性:提供清晰直观的 API 和静态工具方法
  • 可扩展性:无缝集成 Spring Boot 服务和控制器
  • 跨平台:兼容所有支持 Java 的操作系统
  • 开源协议:基于 Apache License,可自由使用和修改

这些特性使 Java Diff Utils 成为 Java 应用中实现可靠文本比较功能的理想选择。

3. 快速搭建环境

在深入实战前,我们通过 Spring Initializr 创建一个简单的 Spring Boot Maven 项目。

虽然 Java Diff Utils 可在纯 Java 环境中手动管理 JAR 使用,但 Spring Boot + Maven 通过 pom.xml 自动处理依赖,显著简化了配置。这种方式不仅减少设置时间,还确保了环境间的一致性和可移植性——Maven 会自动下载、管理和解析所有依赖。

pom.xml 中添加 Java Diff Utils 依赖

<dependency>
    <groupId>io.github.java-diff-utils</groupId>
    <artifactId>java-diff-utils</artifactId>
    <version>4.12</version>
</dependency>

配置完成后,Maven 会确保在编译和运行时提供正确版本的库。现在可以直接使用核心类如 DiffUtilsPatchUnifiedDiffUtils。这些类都是工具类,无需显式实例化,可轻松集成到服务层、控制器或独立组件中。

4. Java Diff Utils 实战应用

本节将通过构建基础组件,演示 Java Diff Utils 在多种场景下的使用。我们将探索核心用例:内容比较、差异生成、补丁应用和并排视图构建。

4.1. 字符串列表比较

创建工具类 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));
}

4.2. 生成统一差异格式

创建 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 测试验证差异生成:

@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")));
}

4.3. 应用补丁

创建 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);
    }
}

先计算差异,再应用补丁将原始内容转换为修订版本。

验证补丁应用效果:

@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);
}

4.4. 构建并排差异视图

创建 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 视图,但暴露的源/目标行数据可用于构建自定义可视化界面。

测试并排视图功能:

@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);
}

5. 总结

本文深入探讨了 Java Diff Utils 的核心功能。作为灵活的开源解决方案,它为 Java 应用中的文本比较提供了强大支持——从基础行级差异到统一差异生成和补丁应用,是构建版本控制或变更追踪系统的基石工具。

凭借极简配置和高度可读的输出,Java Diff Utils 是处理版本化数据、协作编辑工具或文件监控系统的开发者必备利器。

✅ 所有示例代码可在 GitHub 获取。


原始标题:Guide to Java Diff Utils | Baeldung