意图在文本块中的处理方式(Java 13)

Han*_*tsy 2 java string jls java-13

我刚刚尝试了Java 13中的新文本块功能,但遇到了一个小问题。

我已经从Jaxcenter阅读了这篇文章

右三引号将影响格式。

String query = """
            select firstName,
            lastName,
            email
            from User
            where id= ?
        """;

System.out.println("SQL or JPL like query string :\n" + query);
Run Code Online (Sandbox Code Playgroud)

上面的格式效果很好。为了与结束定界符(“”“)对齐,多行字符串在每行之前保留空格。

但是,当我尝试比较以下两个文本块字符串时,它们在输出控制台中的格式相同,但是即使在之后也不相等stripIntent

String hello = """
    Hello,
    Java 13
    """;

String hello2 = """
    Hello,
    Java 13
""";

System.out.println("Hello1:\n" + hello);
System.out.println("Hello2:\n" + hello);

System.out.println("hello is equals hello2:" + hello.equals(hello2));

System.out.println("hello is equals hello2 after stripIndent():" + hello.stripIndent().equals(hello2.stripIndent()));
Run Code Online (Sandbox Code Playgroud)

输出控制台类似于:

String query = """
            select firstName,
            lastName,
            email
            from User
            where id= ?
        """;

System.out.println("SQL or JPL like query string :\n" + query);
Run Code Online (Sandbox Code Playgroud)

我不确定哪里出了问题,还是这是文本块设计的目的?

更新:只需打印hello2 stripIntent,

String hello = """
    Hello,
    Java 13
    """;

String hello2 = """
    Hello,
    Java 13
""";

System.out.println("Hello1:\n" + hello);
System.out.println("Hello2:\n" + hello);

System.out.println("hello is equals hello2:" + hello.equals(hello2));

System.out.println("hello is equals hello2 after stripIndent():" + hello.stripIndent().equals(hello2.stripIndent()));
Run Code Online (Sandbox Code Playgroud)

不会stripIntent预期删除每行之前的空格。

更新:阅读相关的Java文档后,我认为在编译文本块之后,它应该已经删除了该块中各行的左意图。文本块的目的是什么stripIntent我知道在普通字符串上使用它很容易理解。

完整的代码在这里

And*_*lko 5

有一个附带的空白概念。

JEP 355:文本块(预览)

编译时处理

文本块是String类型的常量表达式,就像字符串文字一样。但是,与字符串文字不同,Java编译器通过三个不同的步骤处理文本块的内容:

  • 内容中的行终止符将转换为LF(\ u000A)。这种转换的目的是在跨平台移动Java源代码时遵循最小惊喜的原则。

  • 删除了内容周围附带的空白,以匹配Java源代码的缩进。

  • 内容中的转义序列被解释。作为最后一步执行解释意味着开发人员可以编写转义序列,例如\ n,而无需通过较早的步骤进行修改或删除。

...

附带空白

这是使用点的HTML示例,以可视化开发人员为缩进添加的空间:

String html = """
..............<html>
..............    <body>
..............        <p>Hello, world</p>
..............    </body>
..............</html>
..............""";
Run Code Online (Sandbox Code Playgroud)

由于通常将开始定界符定位为与占用文本块的语句或表达式在同一行上显示,因此对于每行开头有14个可视化空间这一事实没有任何实际意义。在内容中包含这些空格将意味着文本块表示的字符串与由串联字符串文字表示的字符串不同。这会损害迁移,并且会经常出现意外:开发人员不希望在字符串中使用这些空格的可能性很大。同样,通常将结束定界符定位为与内容对齐,这进一步表明14个可视化空间无关紧要。
...
因此,对文本块内容的适当解释是,将每行开头和结尾的附带空白与必要空白区分开。Java编译器通过删除附带的空白来处理内容,以产生开发人员想要的内容。

您的假设

    Hello,
    Java 13
<empty line>
Run Code Online (Sandbox Code Playgroud)

等于

....Hello,
....Java 13
<empty line>
Run Code Online (Sandbox Code Playgroud)

这是不准确的,因为这些是必不可少的空格,并且无论是编译器还是都不会删除它们String#stripIndent

为了清楚起见,让我们继续将附带的空白表示为点。

String hello = """
....Hello,
....Java 13
....""";

String hello2 = """
    Hello,
    Java 13
""";
Run Code Online (Sandbox Code Playgroud)

让我们打印它们。

Hello,
Java 13
<empty line>

    Hello,
    Java 13
<empty line>
Run Code Online (Sandbox Code Playgroud)

让我们String#stripIndent同时调用它们并打印结果。

Hello,
Java 13
<empty line>

    Hello,
    Java 13
<empty line>
Run Code Online (Sandbox Code Playgroud)

要了解为什么什么都没有改变,我们需要查看文档。

String#stripIndent

返回一个值为该字符串的字符串,并从每行的开头和结尾删除附带的空格

然后,如下确定最小压痕(min)。对于每条非空白行(由定义isBlank()),都会对前导空白字符进行计数。即使空白,也将计算最后一行的前导空白字符。最小值是这些计数中的最小值。

对于每条非空白行,将删除最小的前导空白字符,并删除所有尾随的空白字符。空行将替换为空字符串。

对于两个Strings,最小缩进均为0

Hello,          // 0
Java 13         // 0    min(0, 0, 0) = 0 
<empty line>    // 0

    Hello,      // 4
    Java 13     // 4    min(4, 4, 0) = 0
<empty line>    // 0
Run Code Online (Sandbox Code Playgroud)

String#stripIndent 使开发人员可以访问编译器使用的Java版本的重新缩进算法。

杰普355

重新缩进算法在Java语言规范中是规范性的。开发人员将可以通过String::stripIndent新的实例方法访问它。

JEP 355规范

由文本块表示的字符串不是内容中字符的文字序列。而是由文本块表示的字符串是按顺序对内容应用以下转换的结果:

  1. 行终止符被标准化为ASCII LF字符(...)

  2. 偶然的空格被删除,就像通过String::stripIndent对内容中的字符执行一样

  3. 转义序列被解释为字符串字面量。