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

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

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

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

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

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


当前回答

后期模型JAVA对+和常量字符串进行了优化,在幕后使用了StringBuffer,所以你不想让它使你的代码变得混乱。

它指出了JAVA的一个疏忽,它不像ANSI C在双引号字符串之间只有空白的自动连接,例如:

const char usage = "\n"
"Usage: xxxx <options>\n"
"\n"
"Removes your options as designated by the required parameter <options>,\n"
"which must be one of the following strings:\n"
"  love\n"
"  sex\n"
"  drugs\n"
"  rockandroll\n"
"\n" ;

我想有一个多行字符数组常量,其中嵌入换行是光荣的,所以我可以在没有任何混乱的情况下呈现块,例如:

String Query = "
SELECT
    some_column,
    another column
  FROM
      one_table a
    JOIN
      another_table b
    ON    a.id = b.id
      AND a.role_code = b.role_code
  WHERE a.dept = 'sales'
    AND b.sales_quote > 1000
  Order BY 1, 2
" ;

要做到这一点,需要打败JAVA之神。

其他回答

从问题中还不完全清楚作者是否有兴趣处理某种需要有一些动态值的格式化大字符串,但如果是这种情况,像StringTemplate (http://www.stringtemplate.org/)这样的模板引擎可能非常有用。

下面是一个使用StringTemplate的简单代码示例。实际的模板("Hello, < name >")可以从外部纯文本文件加载。模板中的所有缩进都将被保留,不需要转义。

import org.stringtemplate.v4.*;
 
public class Hello {
    public static void main(String[] args) {
        ST hello = new ST("Hello, <name>");
        hello.add("name", "World");
        System.out.println(hello.render());
    }
}

附注:为了可读性和本地化目的,从源代码中删除大块文本总是一个好主意。

你可以在一个单独的方法中连接你的追加:

public static String multilineString(String... lines){
   StringBuilder sb = new StringBuilder();
   for(String s : lines){
     sb.append(s);
     sb.append ('\n');
   }
   return sb.toString();
}

无论哪种方式,都更喜欢StringBuilder而不是加号符号。

加号被转换为StringBuilder。除非两个字符串都是常量,以便编译器可以在编译时将它们组合在一起。至少,Sun的编译器是这样的,我怀疑大多数(如果不是所有)其他编译器也会这样做。

So:

String a="Hello";
String b="Goodbye";
String c=a+b;

通常生成完全相同的代码:

String a="Hello";
String b="Goodbye":
StringBuilder temp=new StringBuilder();
temp.append(a).append(b);
String c=temp.toString();

另一方面:

String c="Hello"+"Goodbye";

等于:

String c="HelloGoodbye";

也就是说,为了可读性,在多行中使用加号将字符串字面量分开并不会受到惩罚。

当我读到多行语法确实是为jdk7计划的(在java存在了多少年之后?)时,我有点恼火。有趣的是,甚至还没有readAll()函数用于读取文件的完整内容(仅从jdk7读取,啊啊),因此下面的代码读取单行。

/*
  MakeMultiline v1.0 (2010) - Free to use and copy.

  Small gadget to turn text blobs into one java string literal
  (doing the split in lines, adding \n at each end and enclosing
  in double quotes). Does escape quotes encountered in the text blob.

  Useful for working around missing multiline string syntax in java
  prior jdk7. Use with:

     java MakeMultiline "    "
  or
     java MakeMultiline "    " mytextfile.txt
*/

import java.io.*;

class MakeMultiline {
  public static void main(String[] args) {
    try {
      // args[0]: indent
      // args[1]: filename to read (optional; stdin if not given)
      // Beware the nmb of newlines at the end when using stdin!

      String indent = (args.length > 0 ? args[0] : "");
      FileReader fr = null; BufferedReader br;
      if (args.length > 1)
        { fr =  new FileReader(args[1]); br = new BufferedReader(fr); }
      else
        { br = new BufferedReader(new InputStreamReader(System.in)); }
      String s; String res = "";
      while((s = br.readLine()) != null) {
        if (res.length() > 0) res += " +\n";
        res += indent + "\"" + s.replace("\"", "\\\"") + "\\n\"";
      }
      br.close(); if (fr != null) fr.close();
      System.out.println(res + ";");
    }
    catch(Exception e) {
      System.out.println("Exception: " + e);
    }
  }
}

这对我来说是最快的解决办法。(2010-01-27)

我至少看到了一种应该避免使用外部文件处理长字符串的情况:如果这些长字符串是单元测试文件中的预期值,因为我认为测试应该始终以一种不依赖任何外部资源的方式编写。