Java : テキストブロックの基本
テキストブロックは、文字列のリテラル表記の1つです。
エスケープなしで、改行や " (ダブルクォート) 文字を表記できます。
他のプログラミング言語では、ヒアドキュメントとも呼ばれていますね。
本記事では、そんなテキストブロックの基本的な使い方をご紹介します。
注意:
- エスケープシーケンスには、バックラッシュ ( \ ) が使われます。
ただし、環境によっては円記号 ( ¥ ) で表示されることもあります。 - 本記事でも \ と ¥ が混在して表示されるかもしれません。
その場合は、どちらも同じものとしてご理解ください。
概要
テキストブロックは、文字列リテラルの表記方法の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" の文字列となります。
しかし、ソースコード上では、abc と 1234 の前に空白が8個あります。
その空白はどこに消えてしまったのでしょう…
テキストブロックでは、
- 各行のインデント(空白)で最小のものを計算
- 各行に対して、最小インデント分を削除
という処理が行われます。
先ほどの例で、最小インデントを . (ピリオド) で表現して見やすくしてみます。
final String textBlock = """
........abc
........1234
........""";
最後の """ の行も最小インデントの計算対象に含まれます。
この例では、どの行も空白8個分のインデントなので、最小インデントは空白8個となります。
そして、すべての行から空白8個が削除されたものが最終的な文字列となります。
つまり、文字列は "abc\n1234\n" ですね。
次に、各行でインデントが異なる例を見てみましょう。
final String textBlock = """
........<html>
........ <body>
........ <p>あいうえお</p>
........ </body>
........</html>
........""";
最小インデントは空白8個です。
<body> や <p> の行はさらにインデントされていますが、その部分は削除されません。
最小インデント (ピリオドの部分) が削除されたものが、最終的な文字列となります。
<html>
<body>
<p>あいうえお</p>
</body>
</html>
補足
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行のテキストを、
- ソースコード上では改行して見やすく
- でも、実際の文字列には改行は含めない
という場面で使えそうです。
プログラマーズ・ガイド
公式ドキュメントとして、テキストブロックのプログラマーズ・ガイドが用意されています。
英文ですが、コード例多めで比較的わかりやすいと思います。
本記事では紹介しきれていない要素もあるので、目を通してみることをおすすめします。
まとめ
テキストブロック、いかがでしたでしょうか。
待ち望んでいたかたも、けっこういらっしゃるのではないでしょうか。
個人的には、ユニットテストで文字列のテストデータを表記したいときに、特にお世話になりそうです。
ソースコードの可読性もあがるので、ぜひ有効に活用していきましょう。