このドキュメントでは、Java SE 14のプレビュー機能であるテキスト・ブロックをサポートするためのJava言語仕様の変更について説明します。 この機能の概要は、JEP 368を参照してください。
変更は、JLSの既存のセクションについて説明しています。 新しいテキストはこのように示され、削除されたテキストはこのように示されます。 必要に応じて、説明と考察が端の方にグレーのボックスで囲まれて記載されています。
第1章: 概要
1.5 プレビュー機能
テキスト・ブロックに関する重要なAPI要素は、次のとおりです。
String
内のメソッドstripIndent
String
内のメソッドtranslateEscapes
第3章: 字句構造
3.10 リテラル
リテラルは、プリミティブ型(4.2)、String
型(4.3.3)またはnull型(4.1)の値のソース・コード表現です。
- Literal:
- IntegerLiteral
- FloatingPointLiteral
- BooleanLiteral
- CharacterLiteral
- StringLiteral
- TextBlock
- NullLiteral
3.10.4 文字リテラル
文字リテラルは、ASCIIの一重引用符で囲まれた文字またはエスケープ・シーケンス(3.10.6)として表されます。 (一重引用符またはアポストロフィ文字は\u0027
です。)
- CharacterLiteral:
'
SingleCharacter'
'
EscapeSequence'
- SingleCharacter:
- InputCharacter (ただし、
'
または\
ではない)
EscapeSequenceの定義は、3.10.6を参照してください。
文字リテラルは常に型char
(4.2.1)です。
文字リテラルは、UTF-16コード・ユニット(3.1)のみを表すことができます。つまり、文字リテラルは、\u0000
~\uffff
の値に制限されています。 補助文字は、一緒に使用されるAPIに応じて、char
シーケンス内のサロゲート・ペアとして、または整数として表す必要があります。
文字リテラルのコンテンツは、左側の'
に続くSingleCharacterまたはEscapeSequenceです。
SingleCharacterまたはEscapeSequenceコンテンツに続く文字が'
以外である場合、コンパイル時にエラーが発生します。
行の終了文字(3.4)が左側の'
の後および右側の'
の前に出現すると、コンパイル時にエラーが発生します。
3.4に規定されているとおり、文字CRおよびLFはInputCharacterではありません。これらはそれぞれ、LineTerminatorを構成しているものとして識別されます。このため、これらは、エスケープ・シーケンス
\
LineTerminator内であっても、文字リテラル内に出現することはできません。
文字リテラルとして表される文字は、コンテンツに対するString::translateEscapes
の実行によるものとして解釈されるエスケープ・シーケンスを持つ文字リテラルのコンテンツです。
char
リテラルの例を次に示します。
'a'
'%'
'\t'
'\\'
'\''
'\u03a9'
'\uFFFF'
'\177'
'™'
Unicodeエスケープは非常に早い段階で処理されるため、値が改行(LF)である文字リテラルを
'\u000a'
と書くことは正しくありません。Unicodeエスケープ\u000a
は、翻訳ステップ1 (3.3)で実際の改行に変換され、この改行がステップ2 (3.4)でLineTerminatorになるため、ステップ3ではこの文字リテラルは有効ではありません。 かわりに、エスケープ・シーケンス'\n'
(3.10.6)を使用する必要があります。 同様に、値が復帰(CR)である文字リテラルを'\u000d'
と書くことは正しくありません。 かわりに、'\r'
を使用します。 最後に、アポストロフィ('
)を含む文字リテラルを'\u0027'
と書くことはできません。
CおよびC++では、文字リテラルに複数文字による表現が含まれる場合がありますが、このような文字リテラルの値は実装定義されます。 Javaプログラミング言語では、文字リテラルは常に正確に1文字を表します。
3.10.5 文字列リテラル
文字列リテラルは、二重引用符で囲まれたゼロ以上の文字で構成されます。 改行などの文字は、エスケープ・シーケンス(3.10.7) (U+0000~U+FFFFの範囲内の文字には1つのエスケープ・シーケンス、U+010000~U+10FFFFの範囲内の文字のUTF-16サロゲート・コード・ユニットには2つのエスケープ・シーケンス)によって表される場合があります。
- StringLiteral:
"
{StringCharacter}"
- StringCharacter:
- InputCharacter (ただし、
"
または\
ではない) - EscapeSequence
文字列リテラルは常に型String
(4.3.3)です。
文字列リテラルのコンテンツは、左側の"
の直後から始まり、右側の"
の直前に終わる文字のシーケンスです。
左側の文字列リテラルのコンテンツ内に行の終了文字が出現すると、コンパイル時にエラーが発生します。"
の後およびそれに応じた右側の"
の前にある
3.4に規定されているとおり、文字CRおよびLFはInputCharacterではありません。これらはそれぞれ、LineTerminatorを構成しているものとして識別されます。このため、これらは、エスケープ・シーケンス
\
LineTerminator内であっても、文字リテラル内に出現することはできません。
文字列リテラルとして表される文字列は、コンテンツに対するString::translateEscapes
の実行によるものとして解釈されるすべてのエスケープ・シーケンスを持つ文字列リテラルのコンテンツです。
文字列リテラルの例を次に示します。
"" // the empty string "\"" // a string containing " alone "This is a string" // a string containing 16 characters "This is a " + // actually a string-valued constant expression, "two-line string" // formed from two string literals
Unicodeエスケープは非常に早い段階で処理されるため、単一の改行(LF)を含む文字列リテラルを
"\u000a"
と書くことは正しくありません。Unicodeエスケープ\u000a
は、翻訳ステップ1 (3.3)で実際の改行に変換され、この改行はステップ2 (3.4)でLineTerminatorになるため、ステップ3ではこの文字列リテラルは有効ではありません。 かわりに、"\n"
(3.10.6)と書く必要があります。 同様に、単一の復帰(CR)を含む文字列リテラルを"\u000d"
と書くことは正しくありません。 かわりに、"\r"
を使用します。 最後に、二重引用符マーク("
)を含む文字列リテラルを"\u0022"
と書くことはできません。長い文字列リテラルは常に、複数の短い部分に分解し、文字列連結演算子
+
(15.18.1)を使用して(場合によってはカッコで囲まれた)式として書くことができます。
実行時には、文字列リテラルは、文字列リテラルによって表される文字列を示すクラスString
(4.3.1、4.3.3)のインスタンスに対する参照です。
さらに、文字列リテラルは常に、クラスString
の同じインスタンスを参照します。 これは、文字列リテラル(または、より一般的には、定数式(15.28)の値である文字列)が、メソッドString.intern
を使用して一意のインスタンスを共有するために「インターン化」されるためです(12.5)。
3.10.6 テキスト・ブロック
テキスト・ブロックは、右側と左側のデリミタで囲まれたゼロ以上の文字で構成されます。 文字はエスケープ・シーケンス(3.10.7)によって表すことができますが、文字列リテラル内でエスケープ・シーケンスを使用して表す必要がある改行および二重引用符の文字はテキスト・ブロック内で直接表すことができます。
- TextBlock:
- " " " { TextBlockWhiteSpace } LineTerminator { TextBlockCharacter } " " "
- TextBlockWhiteSpace:
- WhiteSpace (ただし、LineTerminatorではない)
- TextBlockCharacter:
- InputCharacter (ただし、\ではない)
- EscapeSequence
- LineTerminator
便宜上、3.3、3.4および3.6からの次のプロダクションをここに示します。
- WhiteSpace:
- 「スペース」とも呼ばれるASCII SP文字
- 「水平タブ」とも呼ばれるASCII HT文字
- 「フォーム・フィード」とも呼ばれるASCII FF文字
- LineTerminator
- LineTerminator:
- 「改行」とも呼ばれるASCII LF文字
- 「復帰」とも呼ばれるASCII CR文字
- ASCII LF文字が後に続くASCII CR文字
- InputCharacter:
- UnicodeInputCharacter (ただし、CRまたはLFではない)
- UnicodeInputCharacter:
- UnicodeEscape
- RawInputCharacter
- UnicodeEscape:
- \ UnicodeMarker HexDigit HexDigit HexDigit HexDigit
- RawInputCharacter:
- 任意のUnicode文字
テキスト・ブロックは常に型String
(4.3.3)です。
左側のデリミタは、3つの二重引用符文字("""
)で始まり、ゼロ以上のスペース、タブおよび改行文字が続き、行の終了文字で終わるシーケンスです。
右側のデリミタは、3つの二重引用符文字のシーケンスです。
テキスト・ブロックのコンテンツは、左側のデリミタ行の終了文字の直後から始まり、右側のデリミタの最初の二重引用符の直前に終わる文字のシーケンスです。
文字列リテラル(3.10.5)内の場合とは異なり、行の終了文字がテキスト・ブロックのコンテンツ内に出現しても、コンパイル時にエラーは発生しません。
例3.10.6-1. テキスト・ブロック
複数行の文字列が求められる場合は通常、テキスト・ブロックの方が文字列リテラルの連結よりも読みやすくなります。 たとえば、HTMLのスニペットの次の代替表現を比較します。
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>\n";
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
テキスト・ブロックのいくつかの例を次に示します。
String season = """
winter"""; // the six characters w i n t e r
String period = """
winter
"""; // the seven characters w i n t e r LF
String greeting =
"""
Hi, "Bob"
"""; // the ten characters H i , SP " B o b " LF
String salutation =
"""
Hi,
"Bob"
"""; // the eleven characters H i , LF SP " B o b " LF
String empty = """
"""; // the empty string (zero length)
String quote = """
"
"""; // the two characters " LF
String backslash = """
\\
"""; // the two characters \ LF
テキスト・ブロックではエスケープ・シーケンス"
および\n
の使用が許可されていますが、必ずしも必要ではなく、お薦めしません。 ただし、テキスト・ブロック内でシーケンス"""
を表すには、右側のデリミタの模倣を回避するために、少なくとも1つの"
文字のエスケープが必要です。
例3.10.6-2. テキスト・ブロック内のエスケープ・シーケンス
次のテキストのスニペットは、"文字がエスケープされている場合、読みにくくなります。
String story = """
"When I use a word," Humpty Dumpty said,
in rather a scornful tone, "it means just what I
choose it to mean - neither more nor less."
"The question is," said Alice, "whether you
can make words mean so many different things."
"The question is," said Humpty Dumpty,
"which is to be master - that's all."""";
テキスト・ブロックを使用して別のテキスト・ブロックを示す場合、埋め込まれている右側と左側のデリミタの最初の"をエスケープすることをお薦めします。
String code =
"""
String text = \"""
A text block inside a text block
\""";
""";
テキスト・ブロックによって表される文字列は、コンテンツ内の文字のリテラル・シーケンスではありません。 そうではなく、テキスト・ブロックによって表される文字列は、次の変換を次の順にコンテンツに適用した結果です。
行の終了文字は、次のようにASCII LF文字に正規化されます。
ASCII LF文字が後に続くASCII CR文字は、ASCII LF文字に翻訳されます。
ASCII CR文字は、ASCII LF文字に翻訳されます。
付随する空白は、ステップ1の結果である文字に対する
String::stripIndent
の実行によるものとして削除されます。エスケープ・シーケンスは、ステップ2の結果である文字に対する
String::translateEscapes
の実行によるものとして解釈されます。
例3.10.6-3. テキスト・ブロックのコンテンツに対する変換の順序
エスケープ・シーケンスを最後に解釈することにより、開発者は、\n、\fおよび\rを使用して、行の終了文字の正規化に影響を及ぼさずに文字列の縦方向の書式設定を行い、\bおよび\tを使用して、付随する空白の削除に影響を及ぼさずに文字列の横方向の書式設定を行うことができます。 たとえば、エスケープ・シーケンス\r (CR)を使用した次のテキスト・ブロックについて考えてみます。
String html = """
<html>\r
<body>\r
<p>Hello, world</p>\r
</body>\r
</html>\r
""";
\rエスケープは、行の終了文字がLFに正規化されるまでは解釈されません。 Unicodeエスケープを使用してLF (\u000A)およびCR (\u000D)を視覚化し、|を使用して左マージンを視覚化すると、最終的に次のような結果になります。
|<html>\u000D\u000A
| <body>\u000D\u000A
| <p>Hello, world</p>\u000D\u000A
| </body>\u000D\u000A
|</html>\u000D\u000A
この仕様により、テキスト・ブロックに特定の文字または文字のシーケンスが含まれること、または特定の文字または文字のシーケンスがテキスト・ブロック内にあることが示される場合は、(テキスト・ブロックのコンテンツではなく)テキスト・ブロックによって表される文字列にその文字または文字のシーケンスが含まれることを意味します。
実行時には、テキスト・ブロックは、テキスト・ブロックによって表される文字列を示すクラスString
のインスタンスに対する参照です。
テキスト・ブロックは常に、クラスString
の同じインスタンスを参照します。 これは、テキスト・ブロックによって表される文字列(または、より一般的には、定数式(15.28)の値である文字列)は、一意のインスタンスを共有するために「インターン化」されるためです(12.5)。
例3.10.6-4. 文字列に評価されるテキスト・ブロック
テキスト・ブロックは、型String
の式が許可される場所では常に使用できます。たとえば、文字列の連結内(15.18.1)、クラスString
でのメソッド呼出し内、およびString
要素を使用した注釈内などです。
System.out.println("abc" + """
cde
""");
String math = """
1+1 equals
""" + " " + String.valueOf(2);
String cde = """
abcde""".substring(2);
@Precondition("""
rate > 0 &&
rate <= MAX_REFRESH_RATE
""")
public void setRefreshRate(int rate) { ... }
3.10.6 3.10.7 文字リテラルおよび文字列リテラルのエスケープ・シーケンス
文字リテラル(3.10.4)、文字列リテラル(3.10.5)およびテキスト・ブロック(3.10.6)内で、文字および文字列エスケープ・シーケンスにより、Unicodeエスケープ(3.3)を使用せずに、一部のグラフィック以外の文字をはじめ、一重引用符、二重引用符、バックスラッシュ文字を表現できます。
- EscapeSequence:
\ b
(バックスペースBS、Unicode\u0008
)\ s
(スペースSP、Unicode\u0020
)\ t
(水平タブHT、Unicode\u0009
)\ f
(フォーム・フィードFF、Unicode\u000c
)\ n
(改行LF、Unicode\u000a
)\ r
(復帰CR、Unicode\u000d
)\
LineTerminator (行の継続、Unicode表現なし)\ "
(二重引用符"
、Unicode\u0022
)\ '
(一重引用符'
、Unicode\u0027
)\ \
(バックスラッシュ\
、Unicode\u005c
)- OctalEscape (8進数、Unicode
\u0000
~\u00ff
)
...
8進数のエスケープは、Cとの互換性のために用意されていますが、Unicode値
\u0000
~\u00FF
しか表現できないため、通常はUnicodeエスケープの方が優先されます。
エスケープ・シーケンス内でバックスラッシュに続く文字がLineTerminatorまたはASCII b
、s
、t
、f
、n
、r
、"
、'
、\
、0
、1
、2
、3
、4
、5
、6
、7
ではない場合、コンパイル時にエラーが発生します。
文字リテラル、文字列リテラルまたはテキスト・ブロック内のエスケープ・シーケンスは、\
および末尾の文字を、EscapeSequence文法のUnicodeエスケープが示す単一文字に置き換えることによって解釈されます。 行の継続エスケープ・シーケンスには、対応するUnicodeエスケープがないため、これは何にも置き換えられずに解釈されます。
行の継続エスケープ・シーケンスは、テキスト・ブロック内には出現する可能性がありますが、文字リテラル(3.10.4)または文字列リテラル(3.10.5)内ではそれぞれ、LineTerminatorが許可されないため出現できません。
3.10.7 3.10.8 nullリテラル
null型は、ASCII文字から形成されるnullリテラルであるnull
によって表されるnull参照という1つの値を持ちます。
- NullLiteral:
null
nullリテラルは常にnull型です(4.1)。
その他の変更
次の変更も行われます。
3.1、最終パラグラフ: テキスト・ブロックの記述を追加します。
3.7、最終パラグラフ: テキスト・ブロックの記述を追加します。
4.3.3、3番目のパラグラフ: テキスト・ブロックの記述を追加します。
12.5、2番目のパラグラフ、リストは次のように開始します。
「文字列リテラル(§3.10.5)またはテキスト・ブロック(§3.10.6)を含むクラスまたはインタフェースをロードすると、文字列リテラルまたはテキスト・ブロックを表す新しい
String
オブジェクトが作成される場合があります。 (同じUnicodeコード・ポイントのシーケンスを文字列リテラルまたはテキスト・ブロックとして示す文字列String
のインスタンスが以前にインターン化されている場合は、このようにはなりません。)」15.8.1、5番目の箇条書き: テキスト・ブロックの記述を追加します。
15.28、最初の箇条書き: テキスト・ブロックの記述を追加します。
「プリミティブ型のリテラル(§3.10.1、§3.10.2、§3.10.3、§3.10.4
、§3.10.5)、文字列リテラル(§3.10.5)およびテキスト・ブロック(§3.10.6)。」JVMS 4.7.16.1、
const_value_index
: 「~の値としてプリミティブ定数値または文字列リテラルを示す」から「~の値としてプリミティブ型または型String
の定数を示す」に書き換えます。
「エスケープ」にまつわる用語の説明をした方が望ましい場合があります。
3.3: Javaプログラミング言語のコンパイラ(「Javaコンパイラ」)は、最初にその入力内のUnicodeエスケープを識別し、~他のすべての文字を変更せずに渡します。
補助文字を表すには、連続する2つのUnicodeエスケープが必要です。翻訳ステップの結果、Unicode入力文字のシーケンスが生成されます。~1つのUnicodeエスケープが、U+0000~U+FFFFの範囲内の文字を表すことができます。 U+010000~U+10FFFFの範囲内の補助文字を表すには、連続する2つのUnicodeエスケープが必要です。3.5: ~を処理するUnicodeエスケープの結果として生成される入力文字および行の終了文字
3.10.8: 「nullリテラル」に対する相互参照を3.8、3.9、4.1、15.8.1および15.12.3から更新します。