Skip to main content

Two New Preview Features in Java 25

article
|
open cardboard box on table
Summary

Java 25 introduces two powerful preview features designed to modernize development: a dedicated API for PEM encoding and the "Stable Values" interface. These enhancements simplify cryptographic object handling and offer a memory-efficient, thread-safe alternative to traditional final fields. Explore how these updates streamline security protocols and optimize resource management for the next generation of Java applications.

The latest Java version, Java 25, brings two new preview features that should not be overlooked as they move toward permanent inclusion in the JDK. Java 25 is an LTS (Long-Term Support) release.

New API for PEM

While some may overlook these details, those who deal with exchanging and storing cryptographic objects such as public keys, private keys, certificates, and certificate revocation lists know that these objects are indispensable to sign and verify signatures, verify network connections secured by TLS, and perform other cryptographic operations. The Privacy-Enhanced Mail (PEM) is the standard file format used for exchanging/transporting the cryptographic data. However, once transported, the PEM text needs to be converted back to the cryptographic objects it represents.  An example of such a PEM-encoded text is a public key most may be familiar with:

-----BEGIN PUBLIC KEY-----
MFkwGKLHi09FthKoZIzj0DAQcDQgAEi/kRGOL7wCPTN4KJ2ppeSt5UYB6u
cPjjuKDtFTXbguOIFDdZ65O/8HTUqS/sVzRF+dg7H3/tkQ67hyJD45df==
-----END PUBLIC KEY-----

Prior to Java 25, encoding and decoding such a public key were tedious tasks and involved a lot of coding. Java 25 introduces a new API to facilitate the encoding and decoding of cryptographic objects. Specifically, it introduces a new interface DEREncodable, and three new classes: PEMRecord, PEMEncoder, and PEMDecoder in the java.security package. A typical use of a PEMDecoder is to parse the string, and then extract the specific object needed.

import java.security.PEMDecoder;
import java.security.PrivateKey;
import java.util.Optional;

public class PEMDecoderExample {
   public void loadKey(String pemString) {
       // 1. Create a decoder (using the system-default providers)
       PEMDecoder decoder = PEMDecoder.of();

       // 2. Decode the PEM string into a PrivateKey
       PrivateKey privateKey = decoder.decodeObject(pemString, PrivateKey.class);

       System.out.println("Algorithm: " + privateKey.getAlgorithm());
   }
}

An Alternative to Final Fields

Anyone who has programmed in Java most likely has used the final modifier to declare immutable fields. No catch in that - immutable objects are recommended as a best practice, as they have a stable state and therefore can be shared between multiple threads without any concurrency issues. However, the final fields are quite demanding in that their value must be initialized, whether they are ever used or not. Accordingly, an instance-level final field must be initialized during construction in the constructor, and a class-level final field in the static initializers.  Moreover, we must declare the final fields in the order we want them to be initialized.

Java 25 introduces stable values as an alternative to final fields. They don’t have to be initialized, as final fields must. The initialization of stable values is deferred till they are actually used, which could result in a saving of memory on the heap if a stable value is never used. To this end, Java 25 introduces a new interface java.lang.StableValue<T>. One can use the StableValue.of() factory method to create an unset stable value, or the StableValue.of(T contents) factory method to create a stable value whose value is set with the contents provided.

An example of the Stable Values API uses it to create a data service:

import java.lang.reflect.StableValue;
import java.util.List;

public class DataService {

   // 1. Define the StableValue as static final
   private static final StableValue<List<String>> CACHE = StableValue.of();

   public List<String> getData() {
       // 2. Use computeIfUnset to atomically initialize or retrieve
       return CACHE.computeIfUnset(() -> loadExpensiveData());
   }

   private List<String> loadExpensiveData() {
       System.out.println("Loading from database...");
       return List.of("Data A", "Data B", "Data C");
   }
}


The Stable values API can be used in diverse ways. One can use Stable functions to compute a value, cache it into a backing stable value storage, and use it when needed subsequently. One can use stable values as backing storage for unmodifiable collections. Accordingly, one can create a stable list as an unmodifiable list that is backed by an array of stable values. The advantage of using a stable list over a regular list is that the stable list elements are computed only when they are first accessed. Similarly, one could create a stable map as an unmodifiable map whose keys are known at construction; however, the stable map values are computed only when they are first accessed. 
 


Stable values are thread-safe. Because a stable value can be set only once, if multiple threads are competing to set a stable value, only one will be able to set it, while the other threads are blocked until the stable value is set. Thereafter, the other threads use the value established by the winning thread.
 

About The Author

Deepak is a Sun Certified Java Programmer and Web Component Developer, and has worked in the fields of XML, Java programming and Java EE for ten years. Deepak is the co-author of the Apress book Pro XML Development with Java Technology and was the technical reviewer for the O'Reilly book WebLogic: The Definitive Guide. Deepak was also the technical reviewer for the Course Technology PTR book Ruby Programming for the Absolute Beginner. Deepak is also the author of the Packt Publishing books JDBC 4.0 and Oracle JDeveloper for J2EE DevelopmentProcessing XML Documents with Oracle JDeveloper 11g, EJB 3.0 Database Persistence with Oracle Fusion Middleware 11g, and Java EE Development in Eclipse IDE. Deepak is a Docker Mentor and has published 5 books on Docker and Kubernetes.

Community Sponsor

Lets Hang!

User Comments

0 comments

English