Java 21 has introduced a groundbreaking feature called String Templates. This new feature, which is part of JEP 430, changes the way Java handles strings by combining literal text with dynamic expressions and template processors. This is perfect for situations where you need to use values that are calculated at runtime or entered by the user. String Templates revolutionize the way strings are handled in Java applications. In this article, we will take a closer look at String Templates.

Delving into Template ExpressionsAt the core of String Templates is a new syntax for Java called ‘template expressions’. This syntax enables efficient and secure string interpolation, going beyond simple string concatenation to transform structured text into various object types based on predefined rules.

For instance:

String userName = "Bazlur";String greeting = STR."Welcome, \{userName}";assert greeting.equals("Welcome, Bazlur"); // evaluates to true The Role of STR Template ProcessorThe STR processor, a key component of Java’s string interpolation toolkit, skillfully replaces embedded expressions within templates, converting them into strings. For example, this capability could be particularly useful for creating structured HTML:

``` String pageTitle = "About Us";String message = "Welcome to our site";String htmlContent = STR.""" {pageTitle} {message}

                      """;

``` This example highlights the versatility of template expressions in producing dynamic and secure HTML content.

The FMT Template Processor: A Formatting PowerhouseComplementing STR is FMT, a fellow template processor that boasts enhanced formatting capabilities. FMT’s distinguishing feature lies in its ability to interpret format specifiers similar to those found in java.util.Formatter. This trait makes FMT an ideal choice for generating structured and formatted outputs.

Consider this scenario:

record Building(String name, double length, double width) { double footprint() { return length * width; }}Building[] buildings = { new Building("Tower", 20.5, 15.75), new Building("Warehouse", 40.0, 22.3), new Building("Office", 30.1, 18.6),};String buildingTable = FMT.""" Name Length Width Footprint %-15s\{buildings[0].name} %7.2f\{buildings[0].length} %7.2f\{buildings[0].width} %10.2f\{buildings[0].footprint()} %-15s\{buildings[1].name} %7.2f\{buildings[1].length} %7.2f\{buildings[1].width} %10.2f\{buildings[1].footprint()} %-15s\{buildings[2].name} %7.2f\{buildings[2].length} %7.2f\{buildings[2].width} %10.2f\{buildings[2].footprint()} """;Output: Name Length Width FootprintTower 20.50 15.75 322.88Warehouse 40.00 22.30 892.00Office 30.10 18.60 559.86 This example effectively demonstrates FMT’s proficiency in handling intricate string outputs, such as those found in tabular presentations.

Embracing Custom Template ProcessorsJava 21 extends its capabilities by introducing custom template processors. This flexibility empowers developers to customize string manipulation according to their specific needs.

Consider the following example of a custom processor:

var TEMP = StringTemplate.Processor.of((StringTemplate st) -> { StringBuilder result = new StringBuilder(); Iterator fragmentIterator = st.fragments().iterator(); for (Object value : st.values()) { result.append(fragmentIterator.next()); result.append(value); } result.append(fragmentIterator.next()); return result.toString();});double temperature = 36.5;String healthStatus = TEMP."Body temperature: \{temperature}°C";//Body temperature: 36.5°C In this example, TEMP adeptly handles the combination of text fragments and dynamic values to produce a coherent string.

Let’s explore some additional examples:

Concatenating Strings with a Delimiter (DELIM):

This processor is designed to concatenate a collection of strings, such as elements from a list, using a specified delimiter like a comma.

var DELIM = StringTemplate.Processor.of((StringTemplate st) -> { String delimiter = ", "; var values = st.values(); return values.stream() .flatMap(it -> { if (it instanceof List item) { return item.stream(); } else return Stream.empty(); }).map(String::valueOf) .collect(Collectors.joining(delimiter));});List fruitNames = List.of("Apple", "Banana", "Cherry");String fruits = DELIM."\{fruitNames}";System.out.println(fruits);//Apple, Banana, Cherry The outcome is a well-formatted, comma-separated string, ideal for presenting lists in a clear and concise manner. Although such strings can be created using various techniques, defining a dedicated String processor offers the benefit of reusability. Once established, this processor can be effortlessly incorporated into any part of the source code, aligning with the DRY (Don’t Repeat Yourself) principle. This approach not only simplifies coding but also promotes consistency and efficiency throughout the application.

Formatting Dates (DATE_FORMAT):

This processor transforms LocalDate objects into formatted string representations, utilizing DateTimeFormatter.

var DATE\_FORMAT = StringTemplate.Processor.of((StringTemplate st) -> { var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); return st.values().stream() .map(value -> ((LocalDate) value).format(formatter)) .collect(Collectors.joining(", "));});LocalDate date1 = LocalDate.of(2023, 3, 15);LocalDate date2 = LocalDate.of(2023, 4, 20);String formattedDates = DATE\_FORMAT."\{date1} \{date2}";System.out.println(formattedDates);//2023-03-15, 2023-04-20 The output demonstrates the processor’s ability to convert date objects into a standardized, human-readable date format.

Building a JSON Object (JSON_BUILDER):

Aimed at creating JSON structures dynamically, this processor pairs each fragment with a value to construct a JSONObject.

``` var JSON_BUILDER = StringTemplate.Processor.of((StringTemplate st) -> { JSONObject json = new JSONObject(); Iterator valueIterator = st.values().iterator(); for (String key : st.fragments()) { if (valueIterator.hasNext()) { json.put(key.trim(), valueIterator.next()); } } return json;});String product = "Laptop";double price = 999.99;JSONObject productJson = JSON_BUILDER."product: {product}, price: {price}";System.out.println(productJson);//{"product:":"Laptop",", price:":999.99}This example illustrates the processor’s capability to efficiently generate JSON objects, which is useful in data interchange and API interactions.

Generating XML Elements (XML_GEN): This processor is particularly adept at creating XML structures from Java objects, wrapping each value in XML tags.

var XML\_GEN = StringTemplate.Processor.of((StringTemplate st) -> { var xml = new StringBuilder(""); var values = st.values(); if (!values.isEmpty()) { if (values.getFirst() instanceof List items) { items.forEach(value -> xml.append("") .append(value) .append("")); } } xml.append(""); return xml.toString();});List book = List.of("Book", "Pen", "Notebook");String items = XML\_GEN."\{book}";System.out.println(items);//BookPenNotebook The output exemplifies the processor’s utility in generating structured XML content, which can be essential for data representation and communication in XML-based systems.

Note:

String Template is a preview feature. Here’s how you can enable and use preview features:

Compile with Preview Features: When compiling your Java code, use the --enable-preview flag with the javac command. For example:
javac –enable-preview –release 21 YourJavaFile.java

Run with Preview Features: Similarly, when running your Java application, include the --enable-preview flag with the java command. For example:
java –enable-preview YourJavaFile

IDE Support: If you’re using an Integrated Development Environment (IDE), ensure it supports the latest Java version. Most modern IDEs like IntelliJ IDEA, Eclipse, or Visual Studio Code have options to enable preview features in their project settings.

ConclusionThe introduction of String Templates marks a significant leap forward in Java’s string manipulation capabilities, providing developers with a powerful and versatile toolkit for crafting secure and efficient strings. This new feature is sure to have a transformative impact on Java programming practices.

The post Beyond the Basics: Elevating Java String Handling with Custom Template Processors appeared first on JVM Advent.

```