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

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

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

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

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

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


当前回答

这是你不应该在不考虑它在做什么的情况下使用的东西。但对于一次性脚本,我已经成功地使用了这个方法:

例子:

    System.out.println(S(/*
This is a CRAZY " ' ' " multiline string with all sorts of strange 
   characters!
*/));

代码:

// From: http://blog.efftinge.de/2008/10/multi-line-string-literals-in-java.html
// Takes a comment (/**/) and turns everything inside the comment to a string that is returned from S()
public static String S() {
    StackTraceElement element = new RuntimeException().getStackTrace()[1];
    String name = element.getClassName().replace('.', '/') + ".java";
    StringBuilder sb = new StringBuilder();
    String line = null;
    InputStream in = classLoader.getResourceAsStream(name);
    String s = convertStreamToString(in, element.getLineNumber());
    return s.substring(s.indexOf("/*")+2, s.indexOf("*/"));
}

// From http://www.kodejava.org/examples/266.html
private static String convertStreamToString(InputStream is, int lineNum) {
    /*
     * To convert the InputStream to String we use the BufferedReader.readLine()
     * method. We iterate until the BufferedReader return null which means
     * there's no more data to read. Each line will appended to a StringBuilder
     * and returned as String.
     */
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    StringBuilder sb = new StringBuilder();

    String line = null; int i = 1;
    try {
        while ((line = reader.readLine()) != null) {
            if (i++ >= lineNum) {
                sb.append(line + "\n");
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return sb.toString();
}

其他回答

如果你在属性文件中定义字符串,它看起来会更糟糕。IIRC,它看起来像:

string:text\u000atext\u000atext\u000a

一般来说,在源代码中不嵌入大字符串是一个合理的想法。您可能希望将它们作为资源加载,可能以XML或可读的文本格式加载。文本文件可以在运行时读取,也可以编译成Java源代码。如果你最终把它们放在源代码中,我建议把+放在前面,省略不必要的新行:

final String text = ""
    +"text "
    +"text "
    +"text"
;

如果你有新的行,你可能需要一些join或格式化方法:

final String text = join("\r\n"
    ,"text"
    ,"text"
    ,"text"
);

你可以使用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

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

这个问题有两个答案:

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).

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

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

Java15现在像Python一样支持三引号字符串。

JEP 378: Text Blocks涵盖了此功能,并且包含在JDK 15中。它最初出现在JDK 13中的JEP 355: Text Blocks(预览)和JDK 14中的JEP 368: Text Blocks(第二预览),可以在这些版本中通过——enable-preview javac选项启用。

语法允许这样写:

String s = """
           text
           text
           text
           """;

在此之前,在JDK 12中,JEP 326: Raw String Literals旨在实现类似的功能,但最终被撤回:

请注意:这原本是JDK 12中的预览语言功能,但它已被撤回,并没有出现在JDK 12中。它在JDK 13中被文本块(JEP 355)所取代。