Text Blocks Make Java More Agile

[article]
Summary:

A Java architect has often posed the dilemma of whether to revise existing code around a new feature. Revising code involves a lot of code review and code rewriting. Revising existing Java code is justified only if the benefits of a new feature outweigh the effort needed to revise the code.

A Java architect has often posed the dilemma of whether to revise existing code around a new feature. Revising code involves a lot of code review and code rewriting. Revising existing Java code is justified only if the benefits of a new feature outweigh the effort needed to revise the code. 

Agile software development is an approach that depends on iterative development and simplicity of design. For Agile development, a language must have some essential properties:

  • The code is easy to understand and not cluttered.

  • The code is easy to update.

  • The code is concise.

Java 13 and 14 have added a new Preview language feature that could change how text blocks are coded, and Java applications invariably include a lot of text. The Text blocks feature makes it easier to include blocks of text, which may be further embedded in HTML or JavaScript.  

First, let's discuss what is wrong with how text blocks are coded in Java. 

Problem

The String class represents immutable character strings (sequences of characters) and provides methods for comparing, copying, searching, perusing, concatenating, and extracting strings. String literals (such as “abc”) are implemented as instances of the String class. String literals have no limits on them with regards to their size or content. 

While string literals have no limits on them, their design assumes simple, single-line strings that may contain individual characters such as \n and \t that are easy to escape. String literals are “one-dimensional”  by design. In actual use, a string literal could span multiple lines and may include multiple escape sequences that represent formatting and layout.  

As an example, consider the following string literal that spans across multiple lines and therefore is cluttered with instances of double quotes, concatenation operator (+), and escape sequence for the newline character. 

String html = "<html>"+"\n"+

                  "<body>"+"\n"+

                      "<p>Hello, Java 14</p>"+"\n"+

                   "</body>"+"\n"+

              "</html>";

Not only is the string literal complex to code (or write), it is also difficult to read and maintain. Run the code snippet in jshell and the string literal variable is created.

C:\jdk14\bin>jshell --enable-preview

|  Welcome to JShell -- Version 14-ea

|  For an introduction type: /help intro

jshell> String html = "<html>"+"\n"+

   ...>                   "<body>"+"\n"+

   ...>                       "<p>Hello, Java 14</p>"+"\n"+

   ...>                    "</body>"+"\n"+

   ...>               "</html>";

html ==> "<html>\n<body>\n<p>Hello, Java 14</p>\n</body>\n</html>"

jshell>

Solution

A “Text Block” is a two-dimensional block of text without the shortcomings of the string literal. A Text Block is a preview language feature in JDK 13 and14, which implies that it is impermanent even though fully specified and implemented, and its inclusion in future versions is dependent on user feedback.

What Is a Text Block?

A text block is implemented as a string literal, or rather an enhancement to string literals. A text block is a constant expression just like a string literal. A text block may be used anywhere a string literal is used. A text block provides the following enhancements or improvements to a string literal as it is presently implemented:

  • It is a multi-line string literal without the excessive instances of double quotes (to demarcate sequence of characters on each line), concatenation operator (+), and escape sequence for the newline character.

  • It automatically formats the string (sequence of characters) in a predictable way.

  • It is a two-dimensional block of text and in a sense more “literal” than a string literal as it is presently implemented.

The block of text could be any of the following:

  • messages in natural languages

  • code from other programming languages

  • structured text representing golden files (A golden file is an expected output of a test stored as a separate file; it is called “golden” because it represents the true or expected value).

Syntax of a Text Block

The syntax of text block consists of three components in sequence:

  1. Opening delimiter as three consecutive double-quote characters “”” followed by zero or more white spaces followed by a line terminator. The line terminator may be included directly without a \n. Simply put the opening delimiter must be on its own line. 

  2. Zero or more characters of content, which starts at the first character after the opening delimiter.

  3. Closing delimiter, again as a sequence of  three double quote characters “””. The content ends at the last character before the first double quote of the closing delimiter. The closing delimiter doesn’t need to be on its own line. 

A simple example of a text block usage is as follows in which the “Hello”, “,”, “Java” and “14” are each on a different line. 

String s="""   

         Hello

         , 

         Java 

         14

         """;

Run in jshell with the following output.

jshell> String s="""

   ...>          Hello

   ...>          ,

   ...>          Java

   ...>          14

   ...>          """;

s ==> "Hello\n,\nJava\n14\n"

jshell>

The text block is translated or converted to a string literal:

"Hello\n,\nJava\n14\n"

Taking the example that was used to demonstrate the clutter caused by double quotes, concatenation operator, and escape sequences for the newline character, it could be specified as a text block.

String html = """

              <html>

                   <body>

                      <p>Hello, Java 14</p>

                   </body>

              </html>

              """;

 Run the code snippet in jshell, and the text block is converted to a string literal.

jshell> String html = """

   ...>               <html>

   ...>                    <body>

   ...>                       <p>Hello, Java 14</p>

   ...>                    </body>

   ...>               </html>

   ...>               """;

html ==> "<html>\n     <body>\n        <p>Hello, Java 14</p>\n     </body>\n</html>\n"

As the examples demonstrate, a text block is more readable, easier to code, and  more “literal” than a string literal.

What Is Not a Text Block?

Without a line terminator after the opening sequence of three double quotes, the opening delimiter is not complete. As an example, the following are not text blocks.

String s = """Hello Java 14""";

String s = """    Hello Java 14    """;

String s = """Hello Java 14

                 """;

String s = """\nHello Java 14

""";

The preceding examples generate the same error message.

|  Error:

|  illegal text block open delimiter sequence, missing line terminator

 

As mentioned before, the opening delimiter must be on a separate line without any other text.

More Examples of Text Blocks

A text block is designed for a multi-line block of text, but the text doesn’t have to be multi-line. An example of a text block with a single line is as follows:

String s="""   

                Hello, Java 14

                """;

Run in jshell to create a string literal that ends with a new line.

jshell> String s="""

   ...>                    Hello, Java 14

   ...>                    """;

s ==> "Hello, Java 14\n"

The closing delimiter does not have to be on a separate line and could at the first character after the string content, as an example:

String s="""   

         Hello, Java 14""";

Run in jshell to create a string literal that does not end in a newline character.

jshell> String s="""

   ...>          Hello, Java 14""";

s ==> "Hello, Java 14"

Double quotes may be included directly without using a \” to escape a double quote. 

String s="""   

         "Hello, Java 14" """;

An example of using double quotes directly is as follows:

  String s="""

                 "Hello, Java 14"

                 """;

Run in jshell to generate a string literal with double quotes escaped with a \

jshell> String s="""

   ...>          "Hello, Java 14"

   ...>          """;

s ==> "\"Hello, Java 14\"\n"

A text block is only to improve the readability and development of code. It is not a new construct for strings with a new reference type associated with it. 

Sequences of three characters are reserved for the opening and closing delimiter and should not occur by user code or incidentally in a text block. As an example, an empty string literal within a text block, while apparently permissible, adds three consecutive double quotes as follows:

 String s ="""

                 """"

                 """;

When run in jshell an error is generated.

jshell> String s ="""

   ...>           """"

|  Error:

|  unclosed string literal

|            """"

|               ^

A sequence of three double-quotes could occur even when all the other conditions for a text block are fulfilled as in the following example with a double-quoted string within a text block.

String s="""   

         "Hello, Java 14"""";

When run in jshell an error is generated.

jshell> String s="""

   ...>          "Hello, Java 14"""";

|  Error:

|  unclosed string literal

|           "Hello, Java 14"""";

|                             ^

If the closing delimiter is shifted one character to the right as follows the text block becomes usable.

String s="""   

         "Hello, Java 14" """;

Alternatively, the double-quote preceding the closing delimiter should be escaped with a \.

String s="""   

         "Hello, Java 14\"""";

Run the text block with one of the double-quotes escaped, and an error message is not generated.

jshell> String s="""

   ...>          "Hello, Java 14\"""";

s ==> "\"Hello, Java 14\""

A \ may not be included directly as it is reserved for an escape sequence. The following text block is not supported.

String s = """

           Hello, \ Java 14

           """;

When run in jshell an error message is generated.

jshell> String s = """

   ...>            Hello, \ Java 14

   ...>            """;

|  Error:

|  illegal escape character

|             Hello, \ Java 14

|                     ^

If a \ has to be included it must be escaped as follows.

  String s =  """

              Hello, \\ Java 14

              """;

When run in jshell an error message is not generated.

jshell>   String s =  """

   ...>               Hello, \\ Java 14

   ...>               """;

s ==> "Hello, \\ Java 14\n"

 

A text block may be used with any type of text, such as SQL, HTML, and JSON. As an example, a text block with JSON is specified as follows.

String json="""

            {"time_stamp":"Apr-8-2014-7:06:16-PM-PDT","category": "Notice","type":"WebLogicServer","servername": "AdminServer","code":"BEA-000365","msg": "Server state changed to STANDBY"}

            {"time_stamp":"Apr-8-2014-7:06:17-PM-PDT","category": "Notice","type":"WebLogicServer","servername": "AdminServer","code":"BEA-000365","msg": "Server state changed to STARTING"}

            {"time_stamp":"Apr-8-2014-7:06:18-PM-PDT","category": "Notice","type":"WebLogicServer","servername": "AdminServer","code":"BEA-000360","msg": "Server started in RUNNING mode" }

            """;

Noteworthy is the absence of  escape sequences for newline characters and concatenation operator +.

A polyglot example that demonstrates the decluttering provided by text blocks is running JavaScript code in a Java application using a ScriptEngine.

package jdk14; 

import javax.script.*;

public class TextBlock{

 public static void main(String[] argv){

try{

 ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");

Object obj = engine.eval("""

                         function hello() {

                             print('"Hello, Java 14"');

                         }

                         hello();

                         """);

}catch(ScriptException e){}

}

Without the use of a text block, the JavaScript code becomes almost indecipherable.

package jdk14; 

import javax.script.*;

public class TextBlock{

 

 public static void main(String[] argv){

 

try{

 ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");

Object obj = engine.eval("function hello() {\n" +

                         "    print('\"Hello, Java 14\"');\n" +

                         "}\n" +

                         "\n" +

                         "hello();\n");

}catch(ScriptException e){}

 

Mixing String Literals with Text Blocks

A text block may be concatenated with a string literal using the + operator to generate a new string literal. As an example:

String s="Hello"+

          """   

          , Java 14

          """;

When run in jshell, a new string literal is created.

jshell> String s="Hello"+

   ...>           """

   ...>           , Java 14

   ...>           """;

s ==> "Hello, Java 14\n"

 

 

}

How is a Text Block Indented?

A text block could contain incidental white space in addition to the essential white space. If a text block includes only essential white space, including the desired indentation as in the following example, no extra or incidental white space is included that needs to be removed. No re-indentation is performed. For no extra white space, the content should start on the line after the opening delimiter at exactly the same position as of the first “ of the opening delimiter. The closing delimiter on the last line is positioned directly below the opening limiter.

String html = """

              <html>

                   <body>

                      <p>Hello, Java 14</p>

                   </body>

              </html>

              """;

But consider that a text block has extra or incidental white space as in a variation of the same text block. The extra white space occurs both at the beginning and end of content on each line.

String html = """

                                        <html>                          

                                                   <body>                      

                                                              <p>Hello, Java 14</p>                           

                                                  </body>                                  

                                         </html>                           

                    """;

During compiling, the extra or incidental white space gets removed. How much white space is removed is calculated on the basis of common white space at the beginning of each line including the trailing line on which the closing delimiter is specified. If the closing delimiter is not on a separate line, it is not significant in determining the common white space. A blank line with no content is not used in calculating the common white space. All extra white space at the end of the content on each line is always removed. 

To calculate common white space, first count the number of white space characters leading up to the content or the closing delimiter for each line. The position of the opening delimiter is not significant in determining the common white space while the position of the closing delimiter is. The least count of leading white space characters over all the lines is the common white space. The common white space is removed from each line.   

With re-indentation the preceding text block with extra spaces becomes:

<html>

      <body>

            <p>Hello, Java 14</p>

      </body>

</html>

The indentation that occurs within the content is preserved. 

How are Escape Sequences processed? 

Escape sequences are interpreted last. Escape sequences include the following:

\ b (backspace)

\ t (horizontal)

\ n (linefeed)

\ f (form feed)

\ r (carriage return)

\ " (double quote)

\ ' (single quote)

\ \ (backslash \)

Octal Escape

An example of a text block with escape sequences is as follows:

String s="""   

         \b \"Hello\", \\ \t \'Java 14\'  \377

         """;

Run the code snippet in jshell with the following output.

jshell> String s="""

   ...>          \b \"Hello\", \\ \t \'Java 14\'  \377

   ...>          """;

s ==> "\b \"Hello\", \\ \t 'Java 14'  ÿ\n"

 

Conclusion

A text block is a two-dimensional block of text that spans multiple lines. It is interpreted as an instance of the String class just as a string literal is. A text block makes strings of text more readable and writable. A text block does not need multiple occurrences of escape sequences to specify new lines, concatenation operator (+), and double quotes to demarcate the per-line strings that a string literal spanning multiple lines does. Text blocks make Java code Agile by uncluttering text blocks and making text blocks easy to maintain and update.

 

About the author

CMCrossroads is a TechWell community.

Through conferences, training, consulting, and online resources, TechWell helps you develop and deliver great software every day.