Java HexFormat 怎样把字节数组转换为可读十六进制
来源:17golang原创
时间:2026-11-04 17:02:18 418浏览 收藏
在日志、协议调试或指纹展示中,byte[] 直接打印出来通常不适合阅读。Java 17 引入的 HexFormat 可以把字节数组转换成连续或带分隔符的十六进制文本,也能按同一格式解析回来。关键是:数组格式化用 formatHex,单个数值用 toHexDigits,二者的分隔符和前后缀规则不同。
官方 API 文档:https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/HexFormat.html
想得到可读结果,先用HexFormat.ofDelimiter(":").withUpperCase()构造格式,再调用formatHex(bytes);需要回到字节数组时,必须用同一组 delimiter、prefix 和 suffix 调用parseHex。
本文要点:①数组格式化与单值转换分开选 API;②配置对象是不可变副本,可以安全复用;③解析是严格格式匹配,不是“尽量猜测”。
先分清 HexFormat 的两种工作模式
HexFormat 同时覆盖“字节数组”和“primitive 单值”两类任务。字节数组使用 formatHex 或 parseHex,会处理每个字节的两位十六进制字符,以及可选的分隔符、前缀和后缀。单个 byte、int 或 long 使用 toHexDigits,它只关心大小写和固定宽度,不会套用数组格式的 delimiter。
因此,协议字段、指纹和日志行优先建立一个数组格式;需要把一个整数变成固定宽度十六进制时,才直接使用静态转换方法。不要因为方法名相近,就期待 toHexDigits(255) 自动输出数组格式或前缀。
用 formatHex 输出字节数组
最小配置是 HexFormat.of(),输出小写、无分隔符文本。要让日志中的字节边界更明显,可以使用 ofDelimiter,再通过 withUpperCase、withPrefix 或 withSuffix 返回新的格式对象:
import java.util.HexFormat;
public class HexFormatDemo {
public static void main(String[] args) {
// 用冒号分隔并使用大写,适合展示指纹或报文摘要。
HexFormat fingerprint = HexFormat.ofDelimiter(":")
.withUpperCase();
byte[] bytes = {0x00, 0x01, 0x2a, (byte) 0xff};
// formatHex 会为每个字节生成两位十六进制字符。
String text = fingerprint.formatHex(bytes);
System.out.println(text); // 00:01:2A:FF
}
}
如果团队约定每个值带 #,可以继续调用 withPrefix("#")。这些 withXXX 方法返回副本,原来的 fingerprint 不会被修改,所以可以把格式对象定义为共享常量或注入到多个服务中。

用 parseHex 做严格往返
解析时不要只看字符串“像不像十六进制”。parseHex 会按照当前格式检查每个字节的前缀、两位十六进制字符、后缀和字节之间的分隔符;字符非法、分隔符缺失或前后缀不匹配时会抛出 IllegalArgumentException。最稳妥的做法是让产生文本和消费文本的两端共享同一个格式定义:
import java.util.Arrays;
import java.util.HexFormat;
public class HexRoundTrip {
public static void main(String[] args) {
// 解析规则必须与生成端保持一致:冒号分隔、每项带 #、使用小写。
HexFormat format = HexFormat.ofDelimiter(":")
.withPrefix("#")
.withLowerCase();
byte[] original = {0x10, 0x2a, (byte) 0xf0};
String encoded = format.formatHex(original);
try {
// parseHex 只接受完全符合上述格式的文本。
byte[] decoded = format.parseHex(encoded);
System.out.println(Arrays.equals(original, decoded)); // true
} catch (IllegalArgumentException ex) {
// 把格式错误与业务层的校验失败分开记录。
System.err.println("十六进制格式无效:" + ex.getMessage());
}
}
}
这个例子中,#10:#2a:#f0 可以成功解析;若改成 #10-#2a-#f0,分隔符不符就会失败。解析方法不负责替你删除空格、猜测分隔符或修复半个字节,因此外部输入要先明确协议规则。

按规模和边界选择 API
小型日志可以直接调用 formatHex(byte[])。如果只需要数组的一段,使用带 fromIndex 和 toIndex 的重载,注意右端点是排他的,越界会抛出 IndexOutOfBoundsException。对于大数组或连续输出,formatHex(Appendable, byte[]) 可以写入 StringBuilder、Writer 等目标,减少一次完整中间字符串的压力。
还要记住三个边界:所有相关参数默认不能为 null;空数组格式化结果为空字符串;HexFormat 是不可变且线程安全的值类,比较配置应使用 equals,不要用 == 判断两个实例是否相同。
常见问题
为什么 toHexDigits 没有输出冒号或前缀?因为它服务于单个 primitive 的固定宽度转换,只读取大小写设置;delimiter、prefix 和 suffix 只参与数组格式化与解析。
解析时能不能接受大小写混用?十六进制字符本身按大小写不敏感解析,但 delimiter、prefix、suffix 以及它们出现的位置仍必须符合当前格式。若输入来自用户或外部协议,应先定义是否允许空白和其他包装字符,而不是依赖 parseHex 猜测。
把 HexFormat 当成“格式契约”而不只是转换工具,最容易维护:生产端固定配置,消费端复用同一配置;展示需求用 formatHex,单值需求用 toHexDigits,非法输入则在 parseHex 边界显式处理。
-
501 收藏
-
文章 · java教程 | 1个月前 | Java · 异常处理 · 资源管理 · java try-with-resources AutoCloseable close suppressed exception501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
384 收藏
-
310 收藏
-
172 收藏
-
239 收藏
-
392 收藏
-
263 收藏
-
449 收藏
-
103 收藏
-
305 收藏
-
159 收藏
-
257 收藏
-
439 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习