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

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

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

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

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

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


当前回答

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

其他回答

遗憾的是,Java没有多行字符串字面量。您要么必须连接字符串字面量(使用+或StringBuilder是最常见的两种方法),要么从单独的文件中读取字符串。

对于大的多行字符串文字,我倾向于使用一个单独的文件,并使用getResourceAsStream() (Class类的一个方法)读取它。这使得查找文件变得很容易,因为您不必担心当前目录与代码安装的位置。它还使打包更容易,因为您实际上可以将文件存储在jar文件中。

假设你在一个名为Foo的类中。就像这样做:

Reader r = new InputStreamReader(Foo.class.getResourceAsStream("filename"), "UTF-8");
String s = Utils.readAll(r);

另一个烦恼是Java没有标准的“将这个Reader中的所有文本读入字符串”方法。写起来很简单:

public static String readAll(Reader input) {
    StringBuilder sb = new StringBuilder();
    char[] buffer = new char[4096];
    int charsRead;
    while ((charsRead = input.read(buffer)) >= 0) {
        sb.append(buffer, 0, charsRead);
    }
    input.close();
    return sb.toString();
}

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

例子:

    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();
}

Java 13预览:

Text Blocks Come to Java. Java 13 delivers long-awaited multiline string by Mala Gupta With text blocks, Java 13 is making it easier for you to work with multiline string literals. You no longer need to escape the special characters in string literals or use concatenation operators for values that span multiple lines. Text block is defined using three double quotes (""") as the opening and closing delimiters. The opening delimiter can be followed by zero or more white spaces and a line terminator.

例子:

 String s1 = """
 text
 text
 text
 """;

一个不错的选择。

import static some.Util.*;

    public class Java {

        public static void main(String[] args) {

            String sql = $(
              "Select * from java",
              "join some on ",
              "group by"        
            );

            System.out.println(sql);
        }

    }


    public class Util {

        public static String $(String ...sql){
            return String.join(System.getProperty("line.separator"),sql);
        }

    }

我有时使用一个并行groovy类来充当一个字符串包

这里的java类

public class Test {
    public static void main(String[] args) {
        System.out.println(TestStrings.json1);
        // consume .. parse json
    }
}

以及TestStrings.groovy中令人垂涎的多行字符串

class TestStrings {
    public static String json1 = """
    {
        "name": "Fakeer's Json",
        "age":100,
        "messages":["msg 1","msg 2","msg 3"]
    }""";
}

当然,这只适用于静态字符串。如果我必须在文本中插入变量,我会将整个文件更改为groovy。只要保持强类型实践,它就可以实现。