JDK 17: Hexadecimal Formatting and Parsing
Build 3 of JDK 17 Early Access Builds includes the implementation for JDK-8251989 (“Hex formatting and parsing utility”). This newly introduced functionality for parsing and formatting hexadecimal values is encapsulated in the new class java.util.HexFormat
and is the subject of this post.
Running javap against the new java.util.HexFormat
class provides an easy way to see an overview of its API. The following output is generated from running javap java.util.HexFormat
:
Compiled from "HexFormat.java" public final class java.util.HexFormat { static final boolean $assertionsDisabled; public static java.util.HexFormat of(); public static java.util.HexFormat ofDelimiter(java.lang.String); public java.util.HexFormat withDelimiter(java.lang.String); public java.util.HexFormat withPrefix(java.lang.String); public java.util.HexFormat withSuffix(java.lang.String); public java.util.HexFormat withUpperCase(); public java.util.HexFormat withLowerCase(); public java.lang.String delimiter(); public java.lang.String prefix(); public java.lang.String suffix(); public boolean isUpperCase(); public java.lang.String formatHex(byte[]); public java.lang.String formatHex(byte[], int, int); public <A extends java.lang.Appendable> A formatHex(A, byte[]); public <A extends java.lang.Appendable> A formatHex(A, byte[], int, int); public byte[] parseHex(java.lang.CharSequence); public byte[] parseHex(java.lang.CharSequence, int, int); public byte[] parseHex(char[], int, int); public char toLowHexDigit(int); public char toHighHexDigit(int); public <A extends java.lang.Appendable> A toHexDigits(A, byte); public java.lang.String toHexDigits(byte); public java.lang.String toHexDigits(char); public java.lang.String toHexDigits(short); public java.lang.String toHexDigits(int); public java.lang.String toHexDigits(long); public java.lang.String toHexDigits(long, int); public boolean isHexDigit(int); public int fromHexDigit(int); public int fromHexDigits(java.lang.CharSequence); public int fromHexDigits(java.lang.CharSequence, int, int); public long fromHexDigitsToLong(java.lang.CharSequence); public long fromHexDigitsToLong(java.lang.CharSequence, int, int); public boolean equals(java.lang.Object); public int hashCode(); public java.lang.String toString(); static {}; }
The javap-generated listing shown above indicates that there are two static
factory methods for obtaining an instance of HexFormat
: HexFormat.of()
and HexFormat.ofDelimiter(String)
. Both of these factory methods specify instances of HexFormat
with “preset parameters.” The remainder of the public
methods are instance methods that are generally used for one of five categories of action:
- Instruct the
HexFormat
instance to apply different parameters than the preset parameters the instance was instantiated with - Indicate configured parameters of
HexFormat
instance - Convert to and from hexadecimal representations
- Indicate characteristics of characters and character sequences
- Overridden
Object
methods:toString()
,equals(Object)
,hashCode()
The class-level Javadoc for HexFormat
‘s summarizes the purposes of the HexFormat
class in a single sentence: “HexFormat
converts between bytes and chars and hex-encoded strings which may include additional formatting markup such as prefixes, suffixes, and delimiters.” That class-level Javadoc-based documentation also provides useful examples of applying the HexFormat
class to covert between these types and to apply prefixes, suffixes, and delimiters. The class-level documentation further explains that the HexFormat
class is “immutable and threadsafe” and is a “value-based class.”
In the last version of HexFormat
class source code that I saw, it was advertising “@since 16“, which is one piece of evidence of the work that has been invested in this class in terms of implementation, review, and incorporated feedback (the 33 commits is another piece of evidence). The official release of HexFormat
is actually JDK 17, but the JDK 17 Early Access API Documentation still shows “@since 16” as of this writing.
In this post, I provide some simple examples of applying HexFormat
and these code listings are available on GitHub. Fortunately, the class-level Javadoc-based API documentation provides really good examples of applying HexFormat
. I like it when classes’ Javadoc shows examples of how to apply those classes and the HexFormat
documentation does a good job of covering many aspects of using that class. My examples will cover a smaller portion of the class’s API and is meant solely as an introduction to the basic availability of this class.
Acquiring an Instance of HexFormat
There are two static
methods for acquiring an instance of HexFormat
and one of those is demonstrated here:
/** Instance of {@link HexFormat} used in this demonstration. */ private static final HexFormat HEX_FORMAT_UPPER_CASE = HexFormat.of().withUpperCase();
The withUpperCase()
method instructs the instance of HexFormat
to “use uppercase hexadecimal characters” (“0-9”, “A-F”).
Converting Integers to Hexadecimal
The code snippet shown next demonstrates use of HexFormat.toHexDigits()
:
/** * Demonstrates use of {@link HexFormat#toHexDigits(int)}. */ public void demoIntegerToHexadecimal() { for (int integerValue = 0; integerValue < 17; integerValue++) { out.println("Hexadecimal representation of integer " + integerValue + ": '" + HEX_FORMAT_UPPER_CASE.toHexDigits(integerValue) + "'."); } }
When the above code snippet is executed, the output looks like this:
Hexadecimal representation of integer 0: '00000000'. Hexadecimal representation of integer 1: '00000001'. Hexadecimal representation of integer 2: '00000002'. Hexadecimal representation of integer 3: '00000003'. Hexadecimal representation of integer 4: '00000004'. Hexadecimal representation of integer 5: '00000005'. Hexadecimal representation of integer 6: '00000006'. Hexadecimal representation of integer 7: '00000007'. Hexadecimal representation of integer 8: '00000008'. Hexadecimal representation of integer 9: '00000009'. Hexadecimal representation of integer 10: '0000000A'. Hexadecimal representation of integer 11: '0000000B'. Hexadecimal representation of integer 12: '0000000C'. Hexadecimal representation of integer 13: '0000000D'. Hexadecimal representation of integer 14: '0000000E'. Hexadecimal representation of integer 15: '0000000F'. Hexadecimal representation of integer 16: '00000010'.
Demonstrating HexFormat.isHexDigit(int)
The following code demonstrates HexFormat.isHexDigit(int)
:
/** * Demonstrates use of {@link HexFormat#isHexDigit(int)}. */ public void demoIsHex() { for (char characterValue = 'a'; characterValue < 'i'; characterValue++) { out.println("Is character '" + characterValue + "' a hexadecimal value? " + HEX_FORMAT_UPPER_CASE.isHexDigit(characterValue)); } for (char characterValue = 'A'; characterValue < 'I'; characterValue++) { out.println("Is character '" + characterValue + "' a hexadecimal value? " + HEX_FORMAT_UPPER_CASE.isHexDigit(characterValue)); } }
Here is the output from running the above code snippet:
Is character 'a' a hexadecimal value? true Is character 'b' a hexadecimal value? true Is character 'c' a hexadecimal value? true Is character 'd' a hexadecimal value? true Is character 'e' a hexadecimal value? true Is character 'f' a hexadecimal value? true Is character 'g' a hexadecimal value? false Is character 'h' a hexadecimal value? false Is character 'A' a hexadecimal value? true Is character 'B' a hexadecimal value? true Is character 'C' a hexadecimal value? true Is character 'D' a hexadecimal value? true Is character 'E' a hexadecimal value? true Is character 'F' a hexadecimal value? true Is character 'G' a hexadecimal value? false Is character 'H' a hexadecimal value? false
Demonstrating HexFormat.toString()
The HexFormat
class provides an overriden version of the Object.toString()
method and this is demonstrated in the following code snippet and corresponding output from running that code snippet.
/** * Demonstrates string representation of instance of * {@link HexFormat}. * * The {@link HexFormat#toString()} method provides a string * that shows the instance's parameters (not class name): * "uppercase", "delimiter", "prefix", and "suffix" */ public void demoToString() { out.println("HexFormat.toString(): " + HEX_FORMAT_UPPER_CASE); }
HexFormat.toString(): uppercase: true, delimiter: "", prefix: "", suffix: ""
Other Examples of HexFormat
The Javadoc-based class-level documentation for HexFormat
contains more examples of how to apply this class. The examples demonstrate instantiation methods HexFormat.of()
and HexFormat.ofDelimiter(String)
; demonstrate utility methods toHexDigit(byte)
, fromHexDigits(CharSequence)
, formatHex(byte[])
, and parseHex(String)
; and demonstrate instance specialization methods withUpperCase()
and withPrefix(String)
. I like that the latter examples are “realistic” examples of how operations might be used in practical situations (such as with byte fingerprints).
JDK Uses of HexFormat
The JDK and its tests already use HexFormat
. The following are some examples of this.
- 8252055: Use java.util.HexFormat in java.security
- 8258796: [test] Apply HexFormat to tests for java.security
- 8259493: [test] Use HexFormat instead of adhoc hex utilities in network code and locale SoftKeys
Published on Java Code Geeks with permission by Dustin Marx, partner at our JCG program. See the original article here: JDK 17: Hexadecimal Formatting and Parsing Opinions expressed by Java Code Geeks contributors are their own. |