1. 引言

在Java中,我们通常会编写自己的方法来处理字节和十六进制字符串之间的转换。然而,Java 17引入了java.util.HexFormat,这是一个实用工具类,能够将基本类型、字节数组或字符数组转换为十六进制字符串,反之亦然

在这个教程中,我们将探讨如何使用HexFormat并展示它提供的功能。

2. Java 17之前处理十六进制字符串

十六进制数制使用基数16来表示数字,它由16个符号组成,通常用0-9代表0到9的值,用A-F代表10到15的值。

由于与二进制字符串中的1和0相比更容易理解,这在表示长二进制值时非常受欢迎。

当我们需要在十六进制字符串和字节数组之间进行转换时,开发者通常会使用String.format()方法自定义实现。

这是一个简单易懂的实现,但往往效率不高:

public static String byteArrayToHex(byte[] a) {
    StringBuilder sb = new StringBuilder(a.length * 2);
    for (byte b: a) {
       sb.append(String.format("%02x", b));
    }
    return sb.toString();
}

另一种常见的解决方案是使用Apache Commons Codec库,其中包含一个Hex辅助类:

String foo = "I am a string";
byte[] bytes = foo.getBytes();
Hex.encodeHexString(bytes);

我们的其他教程解释了手动执行这种转换的不同方法

3. Java 17中的HexFormat使用

HexFormat位于Java 17的标准库中,可以处理字节和十六进制字符串之间的转换,并且支持多种格式选项。

3.1. 创建HexFormat

创建HexFormat实例的方式取决于我们是否需要分隔符支持。HexFormat是线程安全的,因此可以在多个线程中使用。

最常见的用法是使用HexFormat.of(),当不关心分隔符支持时:

HexFormat hexFormat = HexFormat.of();

如果需要分隔符支持,可以使用HexFormat.ofDelimiter(":", "delimiter"),例如使用冒号作为分隔符:

HexFormat hexFormat = HexFormat.ofDelimiter(":");

3.2. 字符串格式化

HexFormat允许我们在现有的HexFormat对象上添加前缀、后缀和分隔符格式选项。我们可以利用这些选项来控制正在解析或生成的字符串的格式。

以下是一个使用所有三种选项的例子:

HexFormat hexFormat = HexFormat.of().withPrefix("[").withSuffix("]").withDelimiter(", ");
assertEquals("[48], [0c], [11]", hexFormat.formatHex(new byte[] {72, 12, 17}));

在这种情况下,我们使用简单的of()方法创建对象,然后使用withDelimiter()添加分隔符。

3.3. 字节和十六进制字符串转换

现在我们已经了解了如何创建HexFormat实例,接下来让我们看看如何进行转换。

我们将使用简单的创建方法:

HexFormat hexFormat = HexFormat.of();

然后使用它将字符串转换为byte[]

byte[] hexBytes = hexFormat.parseHex("ABCDEF0123456789");
assertArrayEquals(new byte[] { -85, -51, -17, 1, 35, 69, 103, -119 }, hexBytes);

再反过来:

String bytesAsString = hexFormat.formatHex(new byte[] { -85, -51, -17, 1, 35, 69, 103, -119});
assertEquals("ABCDEF0123456789", bytesAsString);

3.4. 基本类型到十六进制字符串转换

HexFormat也支持将基本类型转换为十六进制字符串:

String fromByte = hexFormat.toHexDigits((byte) 64);
assertEquals("40", fromByte);

String fromLong = hexFormat.toHexDigits(1234_5678_9012_3456L);
assertEquals("000462d53c8abac0", fromLong);

3.5. 大写和小写输出

如示例所示,HexFormat的默认行为是产生小写十六进制值。我们可以通过在创建HexFormat实例时调用withUpperCase()来改变这个行为

upperCaseHexFormat = HexFormat.of().withUpperCase();

尽管小写是默认行为,但withLowerCase()方法也存在。这对于使我们的代码自我文档化并对其他开发者更明确是有用的。

4. 总结

Java 17中引入的HexFormat解决了我们在处理字节和十六进制字符串转换时的传统问题。

在这篇文章中,我们探讨了最常用的情况,但HexFormat还支持更多特定的功能。例如,有更多的转换方法,以及管理完整字节的上半部分和下半部分的能力。

有关HexFormat的官方文档可以在Java 17文档中找到。

如往常一样,本文档中的示例可以在GitHub上找到。