1. Введение
В Java мы обычно пишем собственные методы для обработки преобразований между байтами и шестнадцатеричными строками. Однако в Java 17 представлен java.util.HexFormat
, служебный класс, который позволяет преобразовывать примитивные типы, массивы байтов или массивы символов в шестнадцатеричную строку и наоборот .
В этом руководстве мы рассмотрим, как использовать HexFormat
и продемонстрируем предоставляемые им функции.
2. Работа с шестнадцатеричными строками до Java 17
Шестнадцатеричная система счисления использует основание 16 для представления чисел. Это означает, что он состоит из 16 символов, обычно это символы 0-9 для значений от 0 до 9 и AF для значений от 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 , которая содержит служебный класс Hex :
String foo = "I am a string";
byte[] bytes = foo.getBytes();
Hex.encodeHexString(bytes);
В одном из наших других руководств объясняются различные способы ручного выполнения этого преобразования .
3. Использование HexFormat
в Java 17
HexFormat
можно найти в стандартной библиотеке Java 17, и он может обрабатывать преобразования между байтами и шестнадцатеричными строками . Он также поддерживает несколько вариантов форматирования.
3.1. Создание шестнадцатеричного формата
То, как мы создадим новый экземпляр HexFormat
, зависит от того, нужна ли нам поддержка разделителей или нет . HexFormat
является потокобезопасным, поэтому один экземпляр можно использовать в нескольких потоках.
HexFormat.of()
является наиболее распространенным вариантом использования, который мы используем, когда нам не нужна поддержка разделителей:
HexFormat hexFormat = HexFormat.of();
HexFormat.ofDelimiter(“:”)
можно использовать для поддержки разделителей, в этом примере в качестве разделителя используется двоеточие:
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();
Далее воспользуемся этим для преобразования String
в 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
по умолчанию выдает шестнадцатеричное значение в нижнем регистре. Мы можем изменить это поведение, вызвав withUpperCase()
при создании нашего экземпляра HexFormat
:
upperCaseHexFormat = HexFormat.of().withUpperCase();
Несмотря на то, что нижний регистр является поведением по умолчанию, также существует метод withLowerCase() .
Это полезно, чтобы сделать наш код самодокументируемым и явным для других разработчиков.
4. Вывод
Введение HexFormat
в Java 17 решает многие проблемы, с которыми мы традиционно сталкиваемся при выполнении преобразований между байтами и шестнадцатеричными строками.
В этой статье мы рассмотрели наиболее распространенные варианты использования, но HexFormat
также поддерживает более нишевые функции. Например, больше методов преобразования и возможность управлять старшей и нижней половиной полного байта.
Официальная документация по HexFormat
доступна в документации по Java 17 .
Как обычно, примеры, которые мы представили в этой статье, на GitHub закончились .