○テキスト・ブロックとは

テキスト・ブロックは、改行やクォーテーションなどを含んだ文字列を簡単に定義できる新しい文法である。JavaのStringクラスを使って文字列を宣言する場合、通常であれば、改行や引用符は次のようにエスケープ文字を使用して記述する必要がある。また、文字列を複数行に分けて記述したい場合には連結演算子(+)を使わなければならない。次のような具合だ。

String str = "Hello, Mynavi readers,\n" +

"This is an article \n" +

"that introduces new features of the \"modern\" Java platform.\n";

この記述法は非常によく使うにもかかわらず、コードを読みづらくする上に記述量も増えるという問題を抱えていた。テキスト・ブロックを使用した場合、上のコードは次のように記述できる。

String str = """

Hello, Mynavi readers,

This is an article

that introduces new features of the "modern" Java platform.

""";

ダブルクォーテーションを3つつなげたもの(""")が、テキスト・ブロックの開始と終了を表す。テキスト・ブロックの中では、改行などの特殊文字についてもそのまま記述することができる。したがって、このStringをprintfで出力すると次のようになる。

Hello, Mynavi readers,

This is an article

that introduces new features of the "modern" Java platform.

ただし、開始の"""の後には文字列をつなげることはできず、必ず改行しなければならない("""と改行の間の空白は無視される)。

テキスト・ブロックはJEP 378として、仕様の策定と実装が進められている。最初のプレビュー版(JEP 355)が使えるようになったのはJava 13で、その後エスケープ文字の扱いなど若干の仕様変更が加わったものがJEP 368としてJava 14に追加された。予定通り進めば、2020年9月にリリースされるJava 15で正式版となる。

テキスト・ブロックの使用例

○テキスト・ブロックの使い方

テキスト・ブロックは、現時点ではまだプレビュー版なので、普通にコンパイルすると次のようにエラーになってしまう。

$ javac TextBlockSample.java

TextBlockSample.java:3: エラー: テキスト・ブロックはプレビュー機能であり、デフォルトで無効になっています。

String str = """

^

(テキスト・ブロックを有効にするには--enable-previewを使用します)

エラー1個

プレビュー版の機能を使いたい場合は、次のように「--enable-preview」と「--release」の2つのコンパイルオプションを明示的に指定すればよい。今回は対象バージョンがJava 14なので、--releaseには14を指定している。警告が出るが、意図的に使っているのでこれは無視してもよい。

$ javac --enable-preview --release 14 TextBlockSample.java

注意:TextBlockSample.javaはプレビュー言語機能を使用します。

注意:詳細は、-Xlint:previewオプションを指定して再コンパイルしてください。

実行時も、同様に --enable-preview オプションを指定する。

$ java --enable-preview TextBlockSample

Hello, Mynavi readers,

This is an article

that introduces new features of the "modern" Java platform.

ちなみにIntelliJ IDEAでは、次のようにLanguage Levelの指定によってプロジェクト単位でプレビュー機能を使用するか否かを選択できるようになっている。

プレビュー機能を使用するか否かを選択できる

テキスト・ブロックは、内部的には通常のStringと同じなので、次のようにStringリテラルが入れられる場所であればどこでも使うことができる。

System.out.println("""

Hello, Mynavi readers,

This is an article

that introduces new features of the "modern" Java platform.

""");

インデントは、ブロック中の文字列の一番インデントが浅い行が基準になる。次の例の場合、「Hello, Mynavi readers,」がゼロ・インデントで、ほかの行はこの位置を基準に先頭に空白が挿入される。

String str = """

Hello, Mynavi readers,

This is an article

that introduces new features of the "modern" Java platform.

""";

この文字列は、2行目と3行目がインデントされて次のようになる。

Hello, Mynavi readers,

This is an article

that introduces new features of the "modern" Java platform.

テキスト・ブロック内では、行末の空白は無視される。もし、明示的に空白を挿入したい場合は、次のように「\s」を入れればよい。

String str = """

Hello, Mynavi readers,\s

This is an article\s\s

that introduces new features of the "modern" Java platform.

""";

行末の「\s」の部分は、次のようにすべて空白に置き換わる(「_」の部分は実際は空白)。

Hello, Mynavi readers,_

This is an article__

that introduces new features of the "modern" Java platform.

改行をエスケープしたい場合は、行末に「\」を記述する。

String str = """

Hello, Mynavi readers, \

This is an article \

that introduces new features of the "modern" Java platform.

""";

この場合、次のように改行がない文字列になる。

Hello, Mynavi readers, This is an article that introduces new features of the "modern" Java platform.

テキスト・ブロックで定義した文字列は、通常の文字列と同様に文字列連結子(+)で連結することもできる。次の例では、通常の文字列リテラルと、String変数、そしてテキスト・ブロックを連結している。

String target = "マイナビ読者";

String str6 = "Hello, " + target + ",\n" +

"""

This is an article

that introduces new features of the "modern" Java platform.

""";

結果は次のようになる。

Hello, マイナビ読者,

This is an article

that introduces new features of the "modern" Java platform.

Stringの連結を行いたい理由の1つとしは、上のように途中で変数の値を挿入したいということが挙げられる。+で連結してもよいが、Stringクラスに新たに追加されたformatted()メソッドを使って次のようによりシンプルに書くこともできる。

String str = """

Hello, %s,

This is an article

that introduces new features of the "modern" Java platform.

""".formatted("マイナビ読者");

fotmatted()メソッドを使うと、C言語のprintfのような形式で、文字列の途中にフォーマット指定子を使って値を挿入することができる。内部的には、既存のformat()メソッドを使ったフォーマットと同等のものになっている。このメソッドはテキスト・ブロックとセットで使うことを想定して用意されたものなので、Java 14時点ではテキスト・ブロックと同様にまだプレビュー扱いになっている。

○テキスト・ブロックの実践例

実際の開発で、テキスト・ブロックを利用できたらうれ嬉しいシーンをいくつか考えてみよう。次のコードは、HTMLスニペットをコード内に埋め込む際にテキスト・ブロックを使った例である。従来のエスケープ文字だらけの記述に比べれば格段に可読性が上がっている。

String html = """

Hello, Mynavi readers!

""";

SQLのクエリをテキスト・ブロックを使って記述してみると、次のようになる。エスケープ文字がそのまま記述できるのが非常にうれしい。formatted()メソッドを組み合わせれば、一層使い勝手は上がりそうだ。

try(Connection connection = DriverManager.getConnection("URL", "USER", "PASSWORD")) {

Statement statement = connection.createStatement();

String query = """

SELECT *, FROM "employees"

WHERE "role" = 'manager'

ORDER BY "id";

""";

ResultSet resultSet = statement.executeQuery(query);

} catch (SQLException e) {

e.printStackTrace();

}

次のコードは、Scripting APIを利用してJavaScriptコードをJavaプログラム内で実行する例である。スクリプトを直接テキスト・ブロック内に書き込むことができる。

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

try {

String script = """

function hello() {

print('"Hello, Mynavi readers!"');

}

hello();

""";

Object obj = engine.eval(script);

} catch (ScriptException e) {

e.printStackTrace();

}

このように、テキスト・ブロックはシンプルながらコーディング作業を大幅に軽減し、コードの可読性も上げてくれる。プレビュー機能という点に留意する必要はあるが、実用性が高いのでぜひ活用したい新機能だ。