Showing posts with label Java 17. Show all posts
Showing posts with label Java 17. Show all posts

Tuesday, January 19, 2021

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? "
         + HexFormat.isHexDigit(characterValue));
   }
   for (char characterValue = 'A'; characterValue < 'I'; characterValue++)
   {
      out.println("Is character '" + characterValue + "' a hexadecimal value? "
         + HexFormat.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.

Thursday, December 31, 2020

Java Predictions for 2021 on Foojay

Geertjan Wielenga has posted "Java Predictions for 2021" on Foojay Today. It is a collection of predictions about Java in 2021 from eight members of the Java community (Almas Baimagambetov, Stephen Chin, Brice Dutheil, Marcus Hirt, Reza Rahman, Matt Raible, Simon Ritter, and me). The predictions are concisely written and it's interesting to see the overlap between them while at the same time seeing how different parts of "Java" are important to different people. In this post, I elaborate a bit more on my predictions that were included in "Java Predictions for 2021".

I provided two somewhat related predictions for Java in 2021:

  • "Records will likely be finalized in 2021 and will be widely popular with Java developers who are fortunate enough to work on a version of the JDK with final (not preview) Record support.
  • The release of the OpenJDK 17 implementation in 2021 (which will be the foundation of Oracle's LTS version and other community members' LTS versions) will motivate many who are already working on versions of the JDK later than JDK 8 to start moving or investigate moving to JDK 17. However, JDK 8 will remain widely popular (probably will still be used by over half of Java developers), creating (in the long term) a bimodal distribution of most commonly used JDK versions (8 and 17)."

Java Records Final in 2021

The prediction that Java Records will be final in 2021 is not a risky one. Records have a been a "preview" feature in JDK 14 (JEP 359) and JDK 15 (JEP 384) and now JEP 395 "proposes to finalize the feature in JDK 16" (which is currently in Rampdown Phase One and is scheduled to be released for General Availability in March 2021). Because Records have been through two preview releases already, it seems unlikely that they won't be final as of JDK 16. In the event that they do need one more release, JDK 17 should be released in October 2021.

And Then There Were Two: JDK 8 and JDK 17

2021 will see the beginning of a move to a bimodial distribution of JDK releases most commnoly used. With JDK 17's likely release in October 2021, we'll likely see many Java shops that have already migrated to a version of JDK later than JDK 8 move to that newly released JDK 17. There have been some nice additions and improvements to OpenJDK (which is the foundation of several different JDK implementations) that have been added in recent versions of the JDK and JDK 17 will be an "LTS" (Long-term Support) release for many of the JDK implementations. As an "LTS" release, JDK 17 will appeal to Java shops that want to only be on versions with long-term support and JDK 17 will be the first since JDK 11 to have this status for many of the JDK implementations.

JDK 8 appears to still be the most widely used release of the Java even in 2020. There are several metrics and andecdotal evidence that suggest this. One example is the JetBrains 2020 Development Ecosystem survey that suggests that 75% of Java developers responding to the survey use JDK 8 (some of these developers use other versions of JDK as well) and the same chart shows 32% of responding Java developers use JDK 11. For reference, the 2019 and 2018 versions of this same survey indicated that 83% and 84% of Java developers used JDK 8 in 2019 and 2018 respectively.

JDK 8 is a version with long-term support (Oracle, for example, offers "extended support" for JDK 8 through December 2030) in several JDK implementations and some shops appear hesitant to move to JDK 9 with its introduced modularity support (and need for libraries and frameworks to support that as well). For those shops that have already migrated to a version of JDK later than JDK 8, it should be relatively easier to migrate to JDK 17. I think that some JDK 8 shops will be motivated to make the "big move" and, while doing that, will jump directly to JDK 17. However, I expect that we'll still see at least half of JDK developers still using JDK 8 even at the end of 2021. For the half of JDK users already using a version later than JDK 8 (not counting users of version of JDK before JDK 8), I think we'll begin to see them migrate to JDK 17 in 2021 and the following year or two. Within the next year or two, I expect most JDK developers will be working with JDK 8 or JDK 17.

There will, of course, be some small pockets of JDK developers using other versions before JDK 8, between JDK 8 and JDK 17 (perhaps because they use a feature or garbage collector no longer available in JDK 17), and newer versions of JDK as they are released in 2022.

"LTS" Among JDK Providers

The following are some roadmaps of various JDK vendors' JDK implementations that provide insight into each vendor's LTS concept. Although "LTS" often is referring to Oracle's plan regarding their JDK implementation built on top of OpenJDK, other JDK vendors have generally treated these "LTS" releases in similar manner.

  • AdoptOpenJDK Support and Release Roadmap
    • Shows "Java 17" as LTS.
    • States, "In addition, every three years one feature release will be designated as a Long Term Supported (LTS) release. We will produce LTS releases for at least four years."
    • States, "As a general philosophy, AdoptOpenJDK will continue to build binaries for LTS releases as long as the corresponding upstream source is actively maintained."
  • Oracle Java SE Support Roadmap
    • States, "For product releases after Java SE 8, Oracle will designate a release, every three years, as a Long-Term-Support (LTS) release. Java SE 11 is an LTS release."
  • Azul Java Support Roadmap
    • References Long Term Support (LTS) and Medium Term Support (MTS) and states, "Releases designated as LTS are those same LTS releases as designated by Oracle and the OpenJDK community."
  • Amazon Corretto
    • "Amazon Corretto 8 & 11 support extended" states, "Amazon is extending long-term support (LTS) for Amazon Corretto 8 from June 2023 to May 2026 and for Amazon Corretto 11 from August 2024 to September 2027. Long-term support (LTS) for Corretto includes security updates and specific performance enhancements released at least quarterly."

Looking Forward to 2021

Most of us are hoping for a better year in 2021 than we've experienced in 2020. The finalization of Java Records and General Availability of JDK 17 in 2021 are going to be significant positive events for Java developers and I'm hoping that these will only be a small representative sample of positive events and advancements that benefit a much wider population in 2021.