Java : テキストブロックの基本

テキストブロックは、文字列のリテラル表記の1つです。
エスケープなしで、改行や " (ダブルクォート) 文字を表記できます。

他のプログラミング言語では、ヒアドキュメントとも呼ばれていますね。

本記事では、そんなテキストブロックの基本的な使い方をご紹介します。


概要

3.10.6. Text Blocks
A text block consists of zero or more characters enclosed by opening and closing delimiters.

テキストブロックは、文字列リテラルの表記方法の1つとして、Java言語仕様で定義されています。
Java 15 で正式に追加されました。

通常の文字列リテラルでは、

  • 改行 (\n)
  • " (ダブルクォート) 文字

を表記するにはエスケープが必要でした。

しかし、テキストブロックを使うと、それられのエスケープが不要になります。
結果として、読みやすいソースコードとなります。

簡単なコード例

それではコード例を見てみましょう。
まずは改行を使った例です。

// 通常の文字列リテラル
final String str = "abc\n" +
        "123\n" +
        "あいうえお\n";

// テキストブロック
final String textBlock = """
        abc
        123
        あいうえお
        """;

// 内容は一致します。
System.out.println(str.equals(textBlock)); // true

ダブルクォートの例です。
XMLのテストデータなんかを書くときに便利ですね。

// 通常の文字列リテラル
final String str = "<root>\n" +
        "    <child attr=\"abc\"/>\n" +
        "    <child attr=\"xyz\"/>\n" +
        "</root>\n";


// テキストブロック
final String textBlock = """
        <root>
            <child attr="abc"/>
            <child attr="xyz"/>
        </root>
        """;

// 内容は一致します。
System.out.println(str.equals(textBlock)); // true

テキストブロックだと、だいぶ見やすいのが実感できるのではないでしょうか。

基本的な文法

開始と終了

まずは単純な1行の文字列リテラルで見ていきましょう。

// 通常の文字列リテラル
final String str = "abc";

// テキストブロック
final String textBlock = """
        abc""";

System.out.println(str.equals(textBlock)); // true

テキストブロックは

  • 開始 : """ (ダブルクォート3つ) + 改行
  • 終了 : """ (ダブルクォート3つ)

で表記します。
開始の改行がないとコンパイルエラーとなるのでご注意ください。

// コンパイルエラー
final String textBlock1 = """abc""";

// コンパイルエラー
final String textBlock2 = """abc
            """;

改行と " (ダブルクォート)

改行と " (ダブルクォート) はエスケープ不要です。
テキストブロックの一番の利点ですね。

ソースコード上で改行すれば、それは文字列の改行 ( \n ) となります。
また、例えば Windows でソースファイルの改行コードが \r\n (CRLF) だったとしても、テキストブロックでは \n に変換(正規化)されます。

Main.java (ファイルの改行コードCRLF) を実行した例です。

public class Main {

    public static void main(String[] args) {

        final String str = "<root>\n" +
                "    <child attr=\"abc\"/>\n" +
                "    <child attr=\"xyz\"/>\n" +
                "</root>\n";

        final String textBlock = """
                <root>
                    <child attr="abc"/>
                    <child attr="xyz"/>
                </root>
                """;

        // ファイル自体の改行コードは \r\n ですが、\n として一致します。
        System.out.println(str.equals(textBlock)); // true
    }
}

インデント

テキストブロックのインデントは、慣れないと少し奇妙に感じるかもしれません。

final String textBlock = """
        abc
        1234
        """;

//abc
//1234
System.out.println(textBlock);

例えば、上記のテキストブロックは "abc\n1234\n" の文字列となります。

しかし、ソースコード上では、abc1234 の前に空白が8個あります。
その空白はどこに消えてしまったのでしょう…

テキストブロックでは、

  • 各行のインデント(空白)で最小のものを計算
  • 各行に対して、最小インデント分を削除

という処理が行われます。

先ほどの例で、最小インデントを . (ピリオド) で表現して見やすくしてみます。

final String textBlock = """
........abc
........1234
........""";

最後の """ の行も最小インデントの計算対象に含まれます。

この例では、どの行も空白8個分のインデントなので、最小インデントは空白8個となります。
そして、すべての行から空白8個が削除されたものが最終的な文字列となります。

つまり、文字列は "abc\n1234\n" ですね。

次に、各行でインデントが異なる例を見てみましょう。

final String textBlock = """
........<html>
........    <body>
........        <p>あいうえお</p>
........    </body>
........</html>
........""";

最小インデントは空白8個です。
bodyp の行はさらにインデントされていますが、その部分は削除されません。

最小インデント (ピリオドの部分) が削除されたものが、最終的な文字列となります。

<html>
    <body>
        <p>あいうえお</p>
    </body>
</html>

補足

public String stripIndent()
偶然のwhite spaceをあらゆる行の最初と最後から削除して、値がこの文字列である文字列を返します。
...
このメソッドの主な目的は、行のブロックを左にできるだけ奥まで移動しながら、相対的なインデントを保持することです。

Stringクラスに stripIndentというメソッドがあります。
このメソッドは、テキストブロックのインデント削除と同じルールで、文字列からインデントを削除します。

テキストブロックの理解を深めるために、参考にしてみるのもよいかもしれません。

エスケープシーケンス

テキストブロックでもエスケープシーケンスは使えます。
改行(\n)やダブルクォート文字(\")をエスケープシーケンスで表記することもできます。

\t (タブ)の例です。

final String textBlock = """
        abc\txyz
        123\t789
        """;

// ※タブ8の環境で表示した例です。

//abc     xyz
//123     789
System.out.println(textBlock);

\n (改行)の例です。

final String textBlock = """
        aaa\n123\n""";

//aaa
//123
System.out.print(textBlock);

\" (ダブルクォート)の例です。
文字列として """ を表記したいときに便利です。

final String textBlock = """
        final String textBlock = \"""
                abc
                1234
                \""";
        """;

//final String textBlock = """
//        abc
//        1234
//        """;
System.out.println(textBlock);

改行の抑止

テキストブロックで新しく追加されたエスケープシーケンスです。
コード例で見てみましょう。

final String textBlock = """
        aaa\
        123\
        あいうえお\
        """;

//aaa123あいうえお
System.out.println(textBlock);

テキストブロックの各行の最後を \ (バックスラッシュ)にすることで、テキストブロックによる改行を抑止できます。

例えば、非常に長い1行のテキストを、

  • ソースコード上では改行して見やすく
  • でも、実際の文字列には改行は含めない

という場面で使えそうです。

プログラマーズ・ガイド

This guide assembles practical usage advice for text blocks, along with some style guidelines.

公式ドキュメントとして、テキストブロックのプログラマーズ・ガイドが用意されています。
英文ですが、コード例多めで比較的わかりやすいと思います。

本記事では紹介しきれていない要素もあるので、目を通してみることをおすすめします。

まとめ

テキストブロック、いかがでしたでしょうか。
待ち望んでいたかたも、けっこういらっしゃるのではないでしょうか。

個人的には、ユニットテストで文字列のテストデータを表記したいときに、特にお世話になりそうです。

ソースコードの可読性もあがるので、ぜひ有効に活用していきましょう。


関連記事

ページの先頭へ