来自Perl,我肯定错过了在源代码中创建多行字符串的“here-document”方法:

$string = <<"EOF"  # create a three-line string
text
text
text
EOF

在Java中,当我从头开始连接多行字符串时,我必须在每一行上使用繁琐的引号和加号。

有什么更好的选择吗?在属性文件中定义我的字符串?

编辑:有两个答案说StringBuilder.append()比加号更可取。谁能详细解释一下他们为什么这么想?在我看来,这一点也不可取。我正在寻找一种方法来解决多行字符串不是一级语言结构这一事实,这意味着我绝对不想用方法调用取代一级语言结构(字符串连接与加号)。

编辑:为了进一步澄清我的问题,我根本不关心性能。我关心的是可维护性和设计问题。


当前回答

实际上,下面是我迄今为止见过的最干净的实现。它使用注释将注释转换为字符串变量…

/**
  <html>
    <head/>
    <body>
      <p>
        Hello<br/>
        Multiline<br/>
        World<br/>
      </p>
    </body>
  </html>
  */
  @Multiline
  private static String html;

因此,最终结果是变量html包含多行字符串。没有引号,没有加号,没有逗号,只有纯字符串。

该解决方案可在以下URL… http://www.adrianwalker.org/2011/12/java-multiline-string.html

希望有帮助!

其他回答

Java 13及以上版本

Java中现在通过文本块支持多行字符串。在Java 13和14中,这个特性要求你在构建和运行项目时设置——enable-preview选项。在Java 15及以后版本中,由于文本块已成为标准特性,因此不再需要此选项。查看官方的文本块编程指南,了解更多细节。

现在,在Java 13之前,你是这样写查询的:

List<Tuple> posts = entityManager
.createNativeQuery(
    "SELECT *\n" +
    "FROM (\n" +
    "    SELECT *,\n" +
    "           dense_rank() OVER (\n" +
    "               ORDER BY \"p.created_on\", \"p.id\"\n" +
    "           ) rank\n" +
    "    FROM (\n" +
    "        SELECT p.id AS \"p.id\",\n" +
    "               p.created_on AS \"p.created_on\",\n" +
    "               p.title AS \"p.title\",\n" +
    "               pc.id as \"pc.id\",\n" +
    "               pc.created_on AS \"pc.created_on\",\n" +
    "               pc.review AS \"pc.review\",\n" +
    "               pc.post_id AS \"pc.post_id\"\n" +
    "        FROM post p\n" +
    "        LEFT JOIN post_comment pc ON p.id = pc.post_id\n" +
    "        WHERE p.title LIKE :titlePattern\n" +
    "        ORDER BY p.created_on\n" +
    "    ) p_pc\n" +
    ") p_pc_r\n" +
    "WHERE p_pc_r.rank <= :rank\n",
    Tuple.class)
.setParameter("titlePattern", "High-Performance Java Persistence %")
.setParameter("rank", 5)
.getResultList();

多亏了Java 13 Text Blocks,你可以像下面这样重写这个查询:

List<Tuple> posts = entityManager
.createNativeQuery("""
    SELECT *
    FROM (
        SELECT *,
               dense_rank() OVER (
                   ORDER BY "p.created_on", "p.id"
               ) rank
        FROM (
            SELECT p.id AS "p.id",
                   p.created_on AS "p.created_on",
                   p.title AS "p.title",
                   pc.id as "pc.id",
                   pc.created_on AS "pc.created_on",
                   pc.review AS "pc.review",
                   pc.post_id AS "pc.post_id"
            FROM post p
            LEFT JOIN post_comment pc ON p.id = pc.post_id
            WHERE p.title LIKE :titlePattern
            ORDER BY p.created_on
        ) p_pc
    ) p_pc_r
    WHERE p_pc_r.rank <= :rank
    """,
    Tuple.class)
.setParameter("titlePattern", "High-Performance Java Persistence %")
.setParameter("rank", 5)
.getResultList();

可读性强多了,对吧?

支持的想法

IntelliJ IDEA提供了将传统字符串连接块转换为新的多行字符串格式的支持:

Json, html, XML

多行String在编写JSON、HTML或XML时特别有用。

考虑下面的例子,使用String连接来构建一个JSON字符串文字:

entityManager.persist(
    new Book()
    .setId(1L)
    .setIsbn("978-9730228236")
    .setProperties(
        "{" +
        "   \"title\": \"High-Performance Java Persistence\"," +
        "   \"author\": \"Vlad Mihalcea\"," +
        "   \"publisher\": \"Amazon\"," +
        "   \"price\": 44.99," +
        "   \"reviews\": [" +
        "       {" +
        "           \"reviewer\": \"Cristiano\", " +
        "           \"review\": \"Excellent book to understand Java Persistence\", " +
        "           \"date\": \"2017-11-14\", " +
        "           \"rating\": 5" +
        "       }," +
        "       {" +
        "           \"reviewer\": \"T.W\", " +
        "           \"review\": \"The best JPA ORM book out there\", " +
        "           \"date\": \"2019-01-27\", " +
        "           \"rating\": 5" +
        "       }," +
        "       {" +
        "           \"reviewer\": \"Shaikh\", " +
        "           \"review\": \"The most informative book\", " +
        "           \"date\": \"2016-12-24\", " +
        "           \"rating\": 4" +
        "       }" +
        "   ]" +
        "}"
    )
);

由于转义字符和大量的双引号和加号,您几乎无法阅读JSON。

使用Java文本块,JSON对象可以这样写:

entityManager.persist(
    new Book()
    .setId(1L)
    .setIsbn("978-9730228236")
    .setProperties("""
        {
           "title": "High-Performance Java Persistence",
           "author": "Vlad Mihalcea",
           "publisher": "Amazon",
           "price": 44.99,
           "reviews": [
               {
                   "reviewer": "Cristiano",
                   "review": "Excellent book to understand Java Persistence",
                   "date": "2017-11-14",
                   "rating": 5
               },
               {
                   "reviewer": "T.W",
                   "review": "The best JPA ORM book out there",
                   "date": "2019-01-27",
                   "rating": 5
               },
               {
                   "reviewer": "Shaikh",
                   "review": "The most informative book",
                   "date": "2016-12-24",
                   "rating": 4
               }
           ]
        }
        """
    )
);

自从我在2004年使用c#以来,我一直希望在Java中有这个功能,现在我们终于有了它。

一个非常高效且与平台无关的解决方案是使用系统属性的行分隔符和StringBuilder类来构建字符串:

String separator = System.getProperty("line.separator");
String[] lines = {"Line 1", "Line 2" /*, ... */};

StringBuilder builder = new StringBuilder(lines[0]);
for (int i = 1; i < lines.length(); i++) {
    builder.append(separator).append(lines[i]);
}
String multiLine = builder.toString();

你可以使用scala-code,它与java兼容,并且允许用""" "括起来的多行字符串:

package foobar
object SWrap {
  def bar = """John said: "This is
  a test
  a bloody test,
  my dear." and closed the door.""" 
}

(注意字符串内的引号)和来自java:

String s2 = foobar.SWrap.bar ();

这样是否更舒服?

另一种方法,如果你经常处理长文本,应该放在你的源代码中,可能是一个脚本,它从外部文件中获取文本,并将其包装为一个多行java- string,像这样:

sed '1s/^/String s = \"/;2,$s/^/\t+ "/;2,$s/$/"/' file > file.java

这样你就可以很容易地复制粘贴到你的源代码中。

在IntelliJ IDE中,你只需要输入:

""

然后将光标放置在引号内并粘贴字符串。IDE将它扩展为多个连接的行。

这个问题有两个答案:

In you want to stick to pure Java, with Java 14 being released in March 2020, you can leverage the JEP 368 - Text Blocks, in Second Preview mode. Actually the feature is in preview mode in other releases (at least 13 has it). I created and example set here. While this feature is useful, it can be easily abused. Remember that Java requires compilation - having large character arrays in your code can be an easy way to shoot yourself in the leg (if you want a quick change, you will need recompilation - that toolset might not be available to the guy operating your application).

根据我的经验,建议在配置文件中保留大字符串(通常是应用程序操作员可以/应该在运行时更改的字符串)。

总结:负责地使用文本块:)。