エンターテイメント!!

遊戯王好きのJavaエンジニアのブログ。バーニングソウルを会得する特訓中。

Java13リリース前の予習(Text Blocks深堀)

きっかけ

前回記事でJava13の調査したけど、後々になってTextBlocksに疑問が湧いてきたので調査した

過去記事は、書きを参照

suzaku-tec.hatenadiary.jp

355: Text Blocks (Preview)

JEP 355: Text Blocks (Preview)

ダブルクォートだけを表示させたらどうなるか?

テストコード

public class Jep355Sample2 {
  public static void main(String[] args) throws Exception {
    String str = """"""";
    System.out.println(str);
  }
}

期待値

「"」だけが表示される。

答え

$ javac --enable-preview --release 13 Jep355Sample2.java 
Jep355Sample2.java:3: エラー: テキスト・ブロックの開始区切り文字のシーケンスが無効です。行の終了文字がありません
    String str = """"""";
                    ^    
Jep355Sample2.java:3: エラー: テキスト・ブロックの開始区切り文字のシーケンスが無効です。行の終了文字がありません
    String str = """"""";
                       ^

コンパイル時に怒られた。。。

Descriptionをよく読むと、The opening delimiter is a sequence of three double quote characters (""") followed by zero or more white spaces followed by a line terminator. とある。

Google翻訳よ、おらに力を分けてくれ~」と思いながら翻訳すると、「開始区切り文字は、3つの二重引用符( "" ")の後にゼロ個以上の空白が続き、行終端文字が続くシーケンスです。」となる。

期待値通りの出力をするには、下記に変えると行ける。

public class Jep355Sample2 {
  public static void main(String[] args) throws Exception {
    String str = """ 
    " 
    """;
    System.out.println(str);
  }
}

テキストブロックに\nを入れたらどうなるか?

public class Jep355Sample3 {
  public static void main(String[] args) throws Exception {
    String str = """
    hello\nSaga!!
    """;
    System.out.println(str);
  }
}

何を表示させようかと迷ったら、とりあえず佐賀。

期待値

そのまま、「hello\nSaga!!」が表示される

答え

$ java --enable-preview Jep355Sample3
hello
Saga!!

改行されるだと。。。

Descriptionをよく読むと、たしかになんか書いてある。

The content may include line terminators directly, unlike the characters in a string literal. The use of \n in a text block is permitted, but not necessary or recommended. For example, the text block:

"""
line 1
line 2
line 3
"""

is equivalent to the string literal:

"line 1\nline 2\nline 3\n"

or a concatenation of string literals:

"line 1\n" +
"line 2\n" +
"line 3\n"

If a line terminator is not required at the end of the string, then the closing delimiter can be placed on the last line of content. For example, the text block:

"""
line 1
line 2
line 3"""

is equivalent to the string literal:

"line 1\nline 2\nline 3"

ざっくり読むと、「書くこともできるけど、非推奨」的な感じだと思う。
わざわざ「\n」入れるより、改行したほうが楽だろうってことだろうね。。。

たぶん、ほかのエスケープ系の文字も同様の扱いになっている気がする。

疑問

どこでインデントがきまるの?

    String str = """
    hello Saga!!
    """;

上記の実行結果は、下記になる。

$ java --enable-preview Jep355Sample4
hello Saga!!

本来なら、文字列の前にインデントようの空白があるのだが、なぜか表示されない。
意図通りだからいいんだけど、どういうルールなのか気になった。

さっきよりインデントを増やしたら、どうなるのか試したら、今度は、追加したインデントが表示された。

    String str = """
      hello Saga!!
    """;
$ java --enable-preview Jep355Sample4
  hello Saga!!

インデントの位置は、たぶん、もっともインデントが少ないところがベースになるのだろうと予想。

dependenciesをよく読んでいると、2. Incidental white space に、なんかそれっぽい記述がある。
どうも、インデントの決定は、開始の"""以降の最小のインデントで決まるっぽい。

タブ文字は、1文字とカウントされるっぽいので、インデントに使う文字列を統一してないと、予期せぬレイアウト崩れになりそう。
TextBlocksのところだけインデントが1行ごとに違うとかは、面倒くさいから誰もやらないとは思うが、Javaのユーザ数は多いから、居そうだな。。。