How to use Text Blocks in Java 15

dimitrilc
Introduction

Java 15 introduced Text Blocks. The main reason behind Text Blocks is that programmers can write multiline strings without having to specify escapes for the most common scenarios.

Goals

At the end of this tutorial, you would have learned:

  1. How to store multiline String using Text Block.
  2. Some edge cases to watch out for when using Text Blocks.
Prerequisite Knowledge
  1. Basic Java
Tools Required
  1. A Java IDE with support for JDK 15+.
Syntax

A Text Block can be used anywhere a String literal can be used. Instead of one pair of double quotes used in String literals, a Text Block uses 3 pairs of double quotes.

Here is a traditional multiline String of an HTML document:

    var html = "<!DOCTYPE html>\n" +
           "<html>\n" +
           "    <head>\n" +
           "    </head>\n" +
           "    <body>\n" +
           "        <p>Hello World</p>\n" +
           "    </body>\n" +
           "</html>";

And here is a Text Block:

    var html = """
           <!DOCTYPE html>
           <html>
               <head>
               </head>
               <body>
                   <p>Hello World</p>
               </body>
           </html>
           """;

As you can see, the version using the Text Block no longer has to add the new line character (\n) and concatenate every new line. Removing the need for String concatenation also removes all of the extra double quotes () and plus signs (+), improving readability.

Edge Cases

Text Block has compiler support, so syntax errors are mostly obvious. But there are quite a few edge cases that programmers should watch out for when working with Text Blocks.

The Final New Line

If the closing triple quotes are on a new line of their own, Java will insert an extra new line character (\n) at the end.

This method will return a String with an extra new line at the end.

private static String withNewline(){
   return  """
           Hello
           World
           """;
}

While this method will return a String without an extra new line.

private static String noNewline(){
   return """
           Hello
           World""";
}

Both are valid code that will compile, but the behavior will not be flagged by IDEs and can certainly catch programmers off guard.

Leading White Space

IDEs tend to insert extra spaces and tabs when formatting our code, but how does javac (the compiler) determine whether some white space is part of the String?

Take a look at the withNewline() method below. There are at least 16 spaces from the beginning of the line to the word “Hello”.

leading_white_space.png

To simplify the concept, we only need to remember that the starting position of the closing triple quotes is the cutoff point. Everything before that will be discarded by the compiler.

   private static String zeroSpaces(){
       return  """
               Hello
               World
               """;
   }

   private static String eightSpaces(){
       return  """
               Hello
               World
       """;
   }

   private static String sixteenSpaces(){
       return  """
               Hello
               World
""";
   }

The 3 methods above exemplify the different positions of the closing triple quotes. They print:

Hello
World
        Hello
        World
                Hello
                World

When a final new line is purposely skipped by the programmer, you must use the String#indent method to set the indentation of the Text Block.

private static String fourSpaces(){
   return """
           Hello
           World""".indent(4);
}

Output:

    Hello
    World
Trailing White Space

Just like leading white space, trailing white space is also stripped out by the compiler. There are 3 official strategies that you can adapt to preserve trailing white spaces: character substitution, character fence, and octal escape sequence for space. You can find the code for these methods below.

private static String charSub() {
   return """
           Hello$$$$
           World
           """.replace('$', ' ');
}

private static String charFence() {
   return """
           Hello   |
           World|
           """.replace("|\n", "\n");
}

private static String octalEscape() {
   return """
           Hello\040\040\040
           World
           """;
}

It is hard to tell if the output actually preserved the trailing white spaces, but it is possible if you place your cursor at the end of the output in your IDE terminal. In IntelliJ, I can highlight the extra white spaces on the lines that were preserved like the screenshot below.

asd.png

Solution Code
package com.example;

public class Entry {

   public static void main(String[] args){

   }

   private static String noBlock(){
       var html = "<!DOCTYPE html>\n" +
               "<html>\n" +
               "    <head>\n" +
               "    </head>\n" +
               "    <body>\n" +
               "        <p>Hello World</p>\n" +
               "    </body>\n" +
               "</html>";

       return html;
   }

   private static String textBlock(){
       var html = """
               <!DOCTYPE html>
               <html>
                   <head>
                   </head>
                   <body>
                       <p>Hello World</p>
                   </body>
               </html>
               """;

       return html;
   }

   private static String withNewline(){
       return  """
               Hello
               World
               """;
   }

   private static String noNewline(){
       return """
               Hello
               World""";
   }

   private static String zeroSpaces(){
       return  """
               Hello
               World
               """;
   }

   private static String eightSpaces(){
       return  """
               Hello
               World
       """;
   }

   private static String sixteenSpaces(){
       return  """
               Hello
               World
""";
   }

   private static String fourSpaces(){
       return """
               Hello
               World""".indent(4);
   }

   private static String charSub() {
       return """
               Hello$$$$
               World
               """.replace('$', ' ');
   }

   private static String charFence() {
       return """
               Hello   |
               World|
               """.replace("|\n", "\n");
   }

   private static String octalEscape() {
       return """
               Hello\040\040\040
               World
               """;
   }

}
Summary

Because we have given up precision for convenience, it is important to keep these edge cases in mind when working with Text Blocks, especially when storing white space-sensitive documents. For example, XML-based documents are more forgiving than something like Python, Yaml, when white spaces are used incorrectly.

You can find all of the code used in this article here https://github.com/dmitrilc/DaniWebJavaTextBlock/tree/master

44 Views
About the Author

My name is Dimitri Nguyen. I am a Java Developer specializing in backend development on the Java/Spring/MySQL stack.

I can also work on the frontend using Angular/Typescript/JS/HTML/CSS and native Android with Kotlin.

JamesCherrill 4,426 Most Valuable Poster Moderator Featured Poster

I love the way these posts reveal little goodies hat have slipped into Java over time. I failed to notice String.indent (new in Java 12), and that also lead me to discover stripIndent() which arrived with Java 15.

I also love String'sformatted(...)method (new in Java 15) that works so well with SQL commands in a text block

JamesCherrill 4,426 Most Valuable Poster Moderator Featured Poster

ps you may want to add a note about how text blocks can contain single and double quotes with escaping them... it makes a great improvement in readabiltiy for things like sql commands where there are lots of quotes.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts learning and sharing knowledge.