2020/04/17

Java 14 の新機能 (9) - JEP 368: Text Blocks (Second Preview)

JEP 368: Text Blocks (Second Preview)

Java 13 での JEP 355: Text Blocks (Preview) を受けて、仕様を修正しての Second Preview です。まだ Preview レベルなので、明示的に有効化しないと使えません。

テキストブロックとは?

テキストブロックとは、複数行に渡る文字列リテラルの記法です。他の言語では、here document とか here string とか raw string とか verbatim とか呼ばれている記法です。
public class TextBlockSample {
  public static void main(final String[] args) {
    String str1 = "public class TextBlockSample {\n"
                + "  public static void main(final String[] args) {\n"
                + "    String str1 = \"public class TextBlockSample {}\";\n"
                + "  }\n"
                + "}";
    String str2 = """
                  public class TextBlockSample {
                    public static void main(final String[] args) {
                      String str1 = "public class TextBlockSample {}";
                    }
                  }""";
    System.out.println(str1);
    System.out.println(str1.equals(str2));
  }
}

str1 は従来の記法で、str2 がテキストブロック記法です。str1 と str2 は同じ内容を示しています。
public class TextBlockSample {
  public static void main(final String[] args) {
    String str1 = "public class TextBlockSample {}";
  }
}
true

テキストブロック記法では、改行やダブルクオートがエスケープを使わずに表現できていて、すっきり書けているのが分かると思います。

JEP 355 からの変更点

テキストブロックの仕様は JEP 355 で概ね固まっていましたが、JEP 368 で2つのエスケープシーケンスが追加になりました。

\<行末> で改行のキャンセル

テキストブロックは、ブロック内の改行がそのまま改行文字として文字列に含まれる仕様ですが、逆にそれをキャンセルしたい場合に、行末に'\'を置けばよいことになりました。
これはテキストブロック内でのみ有効なエスケープシーケンスです。
    System.out.println("""
                       a\
                       b\
                       c""".equals("abc")); // true

\s で単一の半角スペース

テキストブロックは、行末の半角スペースの連続を全てトリムする仕様です。これを防ぐために \s で半角スペースを表現できるようになりました。これは普通の文字列リテラル内でも使用可能です。
    System.out.println("""
                       a\s\s
                       ab\s
                       abc""".equals("a  \nab \nabc")); // true

テキストブロックの仕様

テキストブロックは、「"""」+改行から始まって「"""」で終わります。評価結果は String 型の値で、それが出現してよい場所ならどこにでも書けます。
中身は、通常の文字列リテラルと異なる点がいくつかあります。

  • 改行がそのまま書ける (LF \u000a になる)
  • \<行末>で改行をキャンセルできる
  • ダブルクオート「"」が (3つ続かない限り) そのまま書ける
  • 行頭、行末の半角スペースが適宜トリムされる (後述)
行頭の半角スペースは、各行のうち一番インデントレベルが浅い位置が基準となり、それより左側のものが全行においてトリムされます。終了の「"""」が行頭に来るときは、そのインデント位置もこの計算に含まれるので注意してください。全行頭に半角スペースが必要なときは \s を使う必要があります。この挙動は、Java 13 から String::stripIndent として実装されています。
System.out.println("""
               a
              b
               c""".equals(" a\nb\n c"));