Java – Text blocks and best practices

In Java, a text block is a multi-line string literal. It means we do not need to get into mess of explicit line terminators, string concatenations, and delimiters otherwise used for writing the normal string literals.

Java text blocks are available in Java 13 (JEP 355) and Java 14 (JEP 368) as preview features. It is scheduled to become a standard feature in Java 15 (JEP 378).

To enable this preview feature, we must use the –enable-preview and –source 14 (two hyphens) flags.

1. Text Block Syntax

  • Text blocks comprise multiple lines of text and uses three double-quote characters (“””) as its opening and closing delimiter.
  • The opening three double-quote characters are always followed by a line terminator.
  • We cannot have the delimiters and text block on a single line. The opening delimiter must be on its own line. Content has to start on next line only.
  • If the text content contains single or double quotes, there is no need to escape them.
String dbSchema = 	"""
			CREATE TABLE 'TEST'.'EMPLOYEE'
			(
			  'ID' INT NOT NULL DEFAULT 0 ,
			  'FIRST_NAME' VARCHAR(100) NOT NULL ,
			  'LAST_NAME' VARCHAR(100) NULL ,
			  'STAT_CD' TINYINT NOT NULL DEFAULT 0 
			);
					""";

While above text block looks very simple, still a lot of things happen under the hood. Let’s explore.

2. A text block is similar to String

  • The instance produced from a text block is of type java.lang.String with the same characteristics as a traditional double quoted string. This includes object representation and interning into string pool.
  • We can use text blocks to pass as method arguments of type String.
  • Text blocks can be used anywhere a string literal can be used. For example, we can use it for string concatenation.
String string = "Hello";
String textBlock = """
					World""";

String joinedString =  string + textBlock;

System.out.println(joinedString);

Program output.

Hello
World

3. Indentation

3.1. Incidental and essential indentations

The text blocks preserve the indentation of its content. To perform this, JEP divides the space into incidental and essential indentations.

To talk in context, let us refer to first example.

String dbSchema = 	"""
			CREATE TABLE 'TEST'.'EMPLOYEE'
			(
			  'ID' INT NOT NULL DEFAULT 0 ,
			  'FIRST_NAME' VARCHAR(100) NOT NULL ,
			  'LAST_NAME' VARCHAR(100) NULL ,
			  'STAT_CD' TINYINT NOT NULL DEFAULT 0 
			);
					""";

System.out.println(dbSchema);

Program output:

|CREATE TABLE 'TEST'.'EMPLOYEE'
|(
|  'ID' INT NOT NULL DEFAULT 0 ,
|  'FIRST_NAME' VARCHAR(100) NOT NULL ,
|  'LAST_NAME' VARCHAR(100) NULL ,
|  'STAT_CD' TINYINT NOT NULL DEFAULT 0
|);

Here, we have indentation of two types:

First indentation is from start of line till the word "CREATE" in all the lines. This can increase or decrease based on various factors such as formatting plugins or the developer’s choice. It is incidental indentation.

Second indentation is from start of character '(' till 'ID'. It is most of the time 4 or 8 spaces long. This should be honored to maintain the intent of indentation of text block. This is called essential indentation.

Java text blocks remove all the incidental indentations and keep only essential indentations.

3.2. Adding some desired indentation

Lets imagine we want to give 2 tabs indentation to left for all the line in the above example. We can do this by carefully positioning the closing triple quotes to move exactly 2 tabs to the left. Put is at the exactly same place from where the essential indentation should pick up.

String dbSchema = 	"""
			CREATE TABLE 'TEST'.'EMPLOYEE'
			(
			  	'ID' INT NOT NULL DEFAULT 0 ,
			  	'FIRST_NAME' VARCHAR(100) NOT NULL ,
			  	'LAST_NAME' VARCHAR(100) NULL ,
			  	'STAT_CD' TINYINT NOT NULL DEFAULT 0 
			);
	""";

System.out.println(dbSchema);					

Program output:

|		CREATE TABLE 'TEST'.'EMPLOYEE'
|		(
|  			'ID' INT NOT NULL DEFAULT 0 ,
|  			'FIRST_NAME' VARCHAR(100) NOT NULL ,
|  			'LAST_NAME' VARCHAR(100) NULL ,
|  			'STAT_CD' TINYINT NOT NULL DEFAULT 0
|		);

Also, note that trailing white space on each line in a text block is also stripped away by the Java compiler.

3.3. Handling TAB

Unfortunately, it is not difficult for the compiler to know how TAB characters are displayed in different editors.

Therefore, the compiler treats a single space character the same as a single TAB character, even though the TAB character might result in white space equivalent up to eight spaces.

4. Line Terminator

Different platforms have different line terminator characters. Java does not get into platform detection and normalizes all line terminators in a text block to be \n.

If the platform line terminator is required then String::replaceAll("\n", System.lineSeparator()) can be used.

String string = "Hello";
String textBlock = """
					World""";

String joinedString =  string + textBlock;

joinedString = joinedString.replaceAll("\n", System.lineSeparator());

System.out.println(joinedString);

5. New Escape Sequences

5.1. Escape line-terminator

Many times, we want to write the content into multiple lines in the program only but they are actually a single string content. In this case we can use line-terminator escape character which is single backslash '\'. It suppresses the inclusion of an implicit newline character.

String dbSchema = """
	CREATE TABLE 'TEST'.'EMPLOYEE'\
	(\
	'ID' INT NOT NULL DEFAULT 0 ,\
	'FIRST_NAME' VARCHAR(100) NOT NULL ,
	'LAST_NAME' VARCHAR(100) NULL ,\
	'STAT_CD' TINYINT NOT NULL DEFAULT 0 \
	);
	""";

System.out.println(dbSchema);					

Program output:

|CREATE TABLE 'TEST'.'EMPLOYEE'('ID' INT NOT NULL DEFAULT 0 ,'FIRST_NAME' VARCHAR(100) NOT NULL ,
'LAST_NAME' VARCHAR(100) NULL ,'STAT_CD' TINYINT NOT NULL DEFAULT 0 );

5.2. Escape incident space stripping to the right

If we do not want to strip the indentation for some reason, we can use '\s' (ASCII character 32, white space) escape sequence. Using it at the end of any line guarantees that the line will have all space characters till '\s' is encountered.

String dbSchema = 	"""
	CREATE TABLE 'TEST'.'EMPLOYEE'          \s
	(                                       \s
	  'ID' INT NOT NULL DEFAULT 0 ,         \s
	   'FIRST_NAME' VARCHAR(100) NOT NULL , \s
	  'LAST_NAME' VARCHAR(100) NULL ,       \s
	  'STAT_CD' TINYINT NOT NULL DEFAULT 0  \s
	);                                      \s
	""";

System.out.println(dbSchema.replaceAll("\s", "."));

Program output. In this program output, I have replaced all the space characters with dot '.' to make you understand its effect.

CREATE.TABLE.'TEST'.'EMPLOYEE'...........
(........................................
..'ID'.INT.NOT.NULL.DEFAULT.0.,..........
...'FIRST_NAME'.VARCHAR(100).NOT.NULL.,..
..'LAST_NAME'.VARCHAR(100).NULL.,........
..'STAT_CD'.TINYINT.NOT.NULL.DEFAULT.0...
);.......................................

6. Best Practices

  1. Only use a text block when it improves the clarity of the code, particularly with multi-line strings.
  2. If a string fits in the usecase, always prefer to use strings. They are better for application performance.
  3. To maintain the desired indentation, always use the position of closing triple quotes relative to the position of the last line on content.
  4. Avoid in-line text blocks within complex expressions such as lambda expressions or stream operations to maintain readability. Consider refactoring to a local variable or to a static final field.
  5. Either use only spaces or only tabs for the indentation of a text block. Mixing white space will lead to a result with irregular indentation.

Drop me your questions in comments.

Happy Learning !!

References:

OpenJDK Guide

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

Leave a Comment

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.