Watercooler
March 25, 2021
5
min read

Modern Java Text Blocks

Michael Inden

In this blog, I will present the long-awaited syntax extension named Text Blocks. They simplify the definition of multi-line strings. These can now be written without tedious concatenations. Even better, you can also do without error-prone escaping, making it easier to handle SQL commands and define JavaScript and JSON in Java source code, among other things. Text Blocks are internally handled like normal strings after their definition, which is why you can call all familiar string methods.

Let's first look at Text Blocks’ syntax before looking at some possible examples of their use.

Basic syntax

Text blocks describe multi-line strings. These begin and end with three quotes each, where the actual content must be specified on a new line:

System.out.println("""
-I am a-
-text block-
""");

Let's look at the output and its indentation:

-I am a-
-text block-

How does the indentation of only two spaces result when there are some initial spaces before the two lines of text in the println() call? The answer is quite simple: the lower three quotes determine the start of the indentation. In addition, the last line will also have a new line added to it, resulting in an extra blank line.

Unless indentation is required, it is often better to include the end of the text block in the last line:

var firstTextBlockNoIndentation = """
-I am a-
-text block-""";
System.out.println(firstTextBlockNoIndentation);

This gives the somewhat more intuitive result of a two-line string without a trailing blank line but without indentation at the beginning of the lines:

-I am a-
-text block-

It should be briefly mentioned again: in that case, you cannot specify indentation anymore.

Special feature: Quotation marks without escaping

In addition to being multiline, double quotes can also be used in text blocks directly in the string – without escaping, with the following exceptions and special features:

  • After the introductory """ there may only be spaces (will be ignored), but nothing else – not even a comment!
  • If the text block should contain three quotation marks, these must be masked. This also applies to the backslash (except at the very end of a line, more on that later).

Let's look at this now with an example:

System.out.println("""
First 'line' simple quotes
Second "line" double quotes
Third line \""" three quotes
Fourth line no quotes, just \\ :-)""");

The output looks like this:

First 'line' simple quotes
Second "line" double quotes
Third line """ three quotes
Fourth line no quotes, just \ :-)

Special feature: Escape sequences

There are two special escape sequences for Text Blocks. These allow fine-grained control of the processing of line breaks and whitespaces: \ (followed by a line break) and \s.

The former can prevent the automatic insertion of line breaks at the end of a text block. The latter helps to preserve whitespace at the end of a text block. Let's look at examples for both.

Escape sequence \

Sometimes you want to split strings into several smaller part so that they fit better on the screen and therefore are easier to read as the longer string:

String literal = "This is a string splitted " +
"in several smaller " +
"strings.";

If this would converted to a text block, then a newline would automatically be inserted at the end of each line. This can be avoided by specifying \ and using the following text block:

String text = """
This is a string splitted \
in several smaller \
strings.\
""";

This will generate the following one-line string:

This is a string splitted in several smaller strings.

Escape sequence \s

The second escape sequence \s is converted into a single space character. It prevents a line break from occurring directly after the text, or more precisely: If there are still spaces at the end of a line, they will be truncated at the end. The default behavior removes additional whitespace at the end of a string and adds the newline directly:

jshell> String original = """
...> Tim
...> Peter
...> Mike """
original ==> "Tim\nPeter\nMike".

For example, with the escape sequence \s we can achieve that all strings have the same length. Let’s assume that we want to make the names all the same length:

jshell> String names = """
...> Tim \s
...> Peter\s
...> Mike \s"""

This produces the following output with three strings, each 6 characters long:

names ==> "Tim \nPeter \nMike "

Please note that, without \s, the strings would be 3, 5, and 4 characters long – as illustrated in the example before.

Tipp: Practice tip – In my opinion, it would have been better if the escape sequence \s would be transformed into no character. Currently, all Text Blocs using the escape sequence \s contain an artificial space at the end.

If you like to limit the characters to the length of the longest string, this is possible by omitting the escape sequence for the longest string:

jshell> String names2 = """
...> Tim \s
...> Michael
...> Mike \s""";
names2 ==> "Tim \nMichael\nMike "

This changes the output so that all texts have the length of the longest name.

Special feature: Placeholders

In Text Blocks you can define placeholders and fill them with values by calling formatted() – in its handling this method is exactly the same as the static method String.format():

String placeholders = """
On "%tF", Michael %s
bought %d books in '%s'.
""".formatted(LocalDate.of(2020, 1, 20), "Inden", 7, "Bremen");

These instructions produce the following output:

On "2020-01-20", Michael Inden
bought 7 books in 'Bremen'.

Example 1: JavaScript

Below we see the definition of a JavaScript code snippet using Text Blocks:

String javaScriptCode = """
function hello() {
print("Hello World");
}
hello();
""";

What an elegant notation! In contrast, with Java 11 you still have to use quite a bit of ugly escaping and line breaks:

String javaScriptCodeOld = "function hello() {\n" +
" print(\"Hello World\");\n" +
"}\n" +
"hello();\n";

Example 2: HTML Code

Also if you want to prepare HTML code in Java, the Text Blocks are very handy. Until now one had to write awkwardly for example the following:

var helloWorldHtmlOld = "<html>\n" +.
" <body>\n" +
" <p>Hello World</p>\n" +.
" </body>\n" +
"</html>";

In fact, it is much more convenient to specify this as follows:

var helloWorldHtml = """
<html>
<body>
<p>Hello World</p>
</body>
</html>""";

Example 3: Definition of JSON/XML

The JSON (JavaScript Object Notation) data format has become an indispensable part of everyday programming routine, especially in the context of REST services. Although native support for JSON in Java SE would be very desirable, it is not in sight (in Java EE, for example, there is the type javax.json.JsonObject). However, Text Blocks make at least a textual description much easier:

String jsonObj = """
{
"name" : "Mike",
"birthday" : "1971-02-07",
"comment" : "Text blocks are nice!"
}
""";

Even simple XML structures can be defined and filled using Text Blocks and placeholders as follows:

String xmlString = """
<customer>
<firstname>%s</firstname>
<lastname>%s</lastname>
<birthday>%s</birthday>
</customer>
""".formatted("Michael", "Inden", "07.02.1971");

As a rule of thumb, you should prefer to use JAXB (Java Architecture for XML Binding) or others to produce such output. This is especially true as the objects to be mapped become more complex.

Conclusion

The Java releases up to and including 13 are rather manageable in terms of their innovations. This is true even for Java 11 as an LTS version. Fortunately, Java 14 brings a good slew of useful enhancement. Text Blocks are one of them.

This blog has shown how Text Blocks can simplify your life as a developer when it comes to defining multi-line strings or handling HTML, JSON, or HTML representations as strings.

Modern Java Text Blocks

March 25, 2021
5
min read

Subscribe to DevDigest

Get a weekly, curated and easy to digest email with everything that matters in the developer world.

Learn more

From developers. For developers.