Java多行string
来自Perl,我确定缺less在源代码中创build多行string的“here-document”方法:
$string = <<"EOF" # create a three line string text text text EOF
在Java中,我必须在每行上都有繁琐的引号和加号,因为我从头开始连接多行string。
有什么更好的select? 在属性文件中定义我的string?
编辑 :两个答案说StringBuilder.append()比加表示法更好。 谁能详细说明他们为什么这么想? 对我来说,这看起来不太可取。 我正在寻找多行string不是一stream的语言结构的事实,这意味着我绝对不想用方法调用来replace一级语言结构(带有加号的string连接)。
编辑 :进一步澄清我的问题,我根本不关心performance。 我关心可维护性和devise问题。
Stephen Colebourne 提出了在Java 7中添加多行string的build议 。
另外,Groovy已经支持多行string 。
这听起来像你想要做一个多线文字,这在Java中不存在。
你最好的select将是只是+
'd在一起的string。 人们提到的其他一些选项(StringBuilder,String.format,String.join)只有在以string数组开头时才是可取的。
考虑这个:
String s = "It was the best of times, it was the worst of times,\n" + "it was the age of wisdom, it was the age of foolishness,\n" + "it was the epoch of belief, it was the epoch of incredulity,\n" + "it was the season of Light, it was the season of Darkness,\n" + "it was the spring of hope, it was the winter of despair,\n" + "we had everything before us, we had nothing before us";
对比StringBuilder
:
String s = new StringBuilder() .append("It was the best of times, it was the worst of times,\n") .append("it was the age of wisdom, it was the age of foolishness,\n") .append("it was the epoch of belief, it was the epoch of incredulity,\n") .append("it was the season of Light, it was the season of Darkness,\n") .append("it was the spring of hope, it was the winter of despair,\n") .append("we had everything before us, we had nothing before us") .toString();
与String.format()
:
String s = String.format("%s\n%s\n%s\n%s\n%s\n%s" , "It was the best of times, it was the worst of times," , "it was the age of wisdom, it was the age of foolishness," , "it was the epoch of belief, it was the epoch of incredulity," , "it was the season of Light, it was the season of Darkness," , "it was the spring of hope, it was the winter of despair," , "we had everything before us, we had nothing before us" );
与Java8 String.join()
:
String s = String.join("\n" , "It was the best of times, it was the worst of times," , "it was the age of wisdom, it was the age of foolishness," , "it was the epoch of belief, it was the epoch of incredulity," , "it was the season of Light, it was the season of Darkness," , "it was the spring of hope, it was the winter of despair," , "we had everything before us, we had nothing before us" );
如果你想为你的特定系统换行,你需要使用System.getProperty("line.separator")
,或者你可以在String.format
使用%n
。
另一个select是将资源放在一个文本文件中,然后只读取该文件的内容。 这对于非常大的string来说更好,以避免不必要的膨胀你的类文件。
在Eclipse中,如果打开选项“粘贴到string文本时转义文本”(在首选项> Java>编辑器>键入)并粘贴多引号string,则会自动为所有字符添加"
和\n" +
你的线。
String str = "paste your text here";
这是一个古老的线程,但一个新的相当优雅的解决scheme(只有一个缺点)是使用自定义注释。
检查: http : //www.adrianwalker.org/2011/12/java-multiline-string.html
编辑:上面的url似乎被打破。 GitHub上托pipe了一个受此项工作启发的项目:
https://github.com/benelog/multiline
public final class MultilineStringUsage { /** <html> <head/> <body> <p> Hello<br/> Multiline<br/> World<br/> </p> </body> </html> */ @Multiline private static String html; public static void main(final String[] args) { System.out.println(html); } }
缺点是你必须激活相应的(提供的)注释处理器。
而且你可能必须configurationEclipse来不自动重新格式化你的javadoc注释。
有人可能会觉得这很奇怪(javadoc注释并不是为了embedded除注释以外的任何内容),但是由于Java中多行string的缺乏最终令人讨厌,所以我觉得这是最差的解决scheme。
另一个选项可能是将长string存储在外部文件中,并将该文件读入string。
这是你不应该使用,而不考虑它在做什么。 但是对于一次性脚本,我已经使用了这个成功的例子:
例:
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(); }
String.join
Java 8为java.lang.String
添加了一个新的静态方法,它提供了一个更好的select:
String.join( CharSequence delimiter , CharSequence... elements )
使用它:
String s = String.join( System.getProperty("line.separator"), "First line.", "Second line.", "The rest.", "And the last!" );
如果你在一个属性文件中定义你的string,它会更糟糕。 IIRC,它会看起来像:
string:text\u000atext\u000atext\u000a
通常这是一个合理的想法,不要将大型stringembedded到源代码中。 您可能需要将它们加载为资源,可能是XML或可读的文本格式。 文本文件可以在运行时读取,也可以编译为Java源代码。 如果你最终把它们放在源代码中,我build议把+
放在前面,省略不必要的新行:
final String text = "" +"text " +"text " +"text" ;
如果你有新的行,你可能需要一些连接或格式化方法:
final String text = join("\r\n" ,"text" ,"text" ,"text" );
除非两个string都是常量,所以编译器可以在编译时将它们组合起来,否则将会将其转换为StringBuilder.append。 至less在Sun的编译器中就是这样,而且如果不是所有其他的编译器都做同样的事情,我会怀疑它。
所以:
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";
也就是说,为了提高可读性,在加上多个符号的行之间打破string文字是没有问题的。
可悲的是,Java没有多行string文字。 您必须连接string文字(使用+或StringBuilder是两种最常见的方法),或者从单独的文件中读取string。
对于大型多行string文字,我倾向于使用单独的文件,并使用getResourceAsStream()
( Class
类的方法getResourceAsStream()
读取它。 这样就很容易find文件,因为您不必担心当前目录与您的代码的安装位置。 这也使包装更容易,因为你实际上可以将文件存储在jar文件中。
假设你在一个名为Foo的类中。 只要做这样的事情:
Reader r = new InputStreamReader(Foo.class.getResourceAsStream("filename"), "UTF-8"); String s = Utils.readAll(r);
另外一个烦恼是Java没有一个标准的“将读者的所有文本读入string”方法。 虽然写起来很容易:
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(); }
由于Java并不支持多行string,所以现在唯一的方法就是使用前面提到的技术来解决这个问题。 我使用上面提到的一些技巧构build了以下Python脚本:
import sys import string import os print 'new String(' for line in sys.stdin: one = string.replace(line, '"', '\\"').rstrip(os.linesep) print ' + "' + one + ' "' print ')'
把它放在一个名为javastringify.py的文件中,将你的string放在一个文件mystring.txt中,然后按如下方式运行它:
cat mystring.txt | python javastringify.py
然后,您可以复制输出并将其粘贴到您的编辑器中。
根据需要修改这个以处理任何特殊情况,但是这适用于我的需要。 希望这可以帮助!
String newline = System.getProperty ("line.separator"); string1 + newline + string2 + newline + string3
但是,最好的select是使用String.format
String multilineString = String.format("%s\n%s\n%s\n",line1,line2,line3);
在IntelliJ IDE中,只需键入:
""
然后将光标放在引号内并粘贴您的string。 IDE将其展开为多个连接线。
您可以使用与java兼容的scala-code,并允许用“”“括起来的多行string:
package foobar object SWrap { def bar = """John said: "This is a test a bloody test, my dear." and closed the door.""" }
(注意string中的引号)和java:
String s2 = foobar.SWrap.bar ();
这是否更舒适…?
另一种方法,如果你经常处理长文本,应该放在你的源代码中,可能是一个脚本,它从外部文件中获取文本,并将其作为一个多行java-String包装,如下所示:
sed '1s/^/String s = \"/;2,$s/^/\t+ "/;2,$s/$/"/' file > file.java
这样你就可以轻松地把它粘贴到你的源代码中。
import org.apache.commons.lang3.StringUtils; String multiline = StringUtils.join(new String[] { "It was the best of times, it was the worst of times ", "it was the age of wisdom, it was the age of foolishness", "it was the epoch of belief, it was the epoch of incredulity", "it was the season of Light, it was the season of Darkness", "it was the spring of hope, it was the winter of despair", "we had everything before us, we had nothing before us" }, "\n");
其实,以下是迄今为止我见过的最清晰的实现。 它使用注释将注释转换为stringvariables…
/** <html> <head/> <body> <p> Hello<br/> Multiline<br/> World<br/> </p> </body> </html> */ @Multiline private static String html;
所以,最终的结果是variableshtml包含多行string。 没有引号,没有加号,没有逗号,只是纯粹的string。
该解决scheme可在以下url获得: http://www.adrianwalker.org/2011/12/java-multiline-string.html
希望有所帮助!
你可以连接你的附加在一个单独的方法,如:
public static String multilineString(String... lines){ StringBuilder sb = new StringBuilder(); for(String s : lines){ sb.append(s); sb.append ('\n'); } return sb.toStirng(); }
无论哪种方式,更喜欢StringBuilder
加号。
请参阅Java Stringfier 。 如果需要,将文本转换为一个StringBuilder Java块转义。
如果你喜欢谷歌的番石榴一样,它可以给一个相当干净的代表性和一个很好,简单的方法来不硬编码你的换行符:
String out = Joiner.on(newline).join(ImmutableList.of( "line1", "line2", "line3"));
另一个我还没有看到的答案是java.io.PrintWriter
。
StringWriter stringWriter = new StringWriter(); PrintWriter writer = new PrintWriter(stringWriter); writer.println("It was the best of times, it was the worst of times"); writer.println("it was the age of wisdom, it was the age of foolishness,"); writer.println("it was the epoch of belief, it was the epoch of incredulity,"); writer.println("it was the season of Light, it was the season of Darkness,"); writer.println("it was the spring of hope, it was the winter of despair,"); writer.println("we had everything before us, we had nothing before us"); String string = stringWriter.toString();
另外事实上, java.io.BufferedWriter
有一个newLine()
方法是未提及的。
一个相当有效和独立于平台的解决scheme将使用行分隔符的系统属性和StringBuilder类来构buildstring:
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();
在属性文件中定义我的string?
属性文件中不允许使用多行string。 你可以在属性文件中使用\ n,但是我认为这不是一个很好的解决scheme。
当使用一长串+时,只有一个StringBuilder被创build,除非String在编译时被确定,在这种情况下没有使用StringBuilder!
唯一一次StringBuilder更有效的是当多个语句被用来构造string。
String a = "a\n"; String b = "b\n"; String c = "c\n"; String d = "d\n"; String abcd = a + b + c + d; System.out.println(abcd); String abcd2 = "a\n" + "b\n" + "c\n" + "d\n"; System.out.println(abcd2);
注意:只有一个StringBuilder被创build。
Code: 0: ldc #2; //String a\n 2: astore_1 3: ldc #3; //String b\n 5: astore_2 6: ldc #4; //String c\n 8: astore_3 9: ldc #5; //String d\n 11: astore 4 13: new #6; //class java/lang/StringBuilder 16: dup 17: invokespecial #7; //Method java/lang/StringBuilder."<init>":()V 20: aload_1 21: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 24: aload_2 25: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 28: aload_3 29: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 32: aload 4 34: invokevirtual #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 37: invokevirtual #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 40: astore 5 42: getstatic #10; //Field java/lang/System.out:Ljava/io/PrintStream; 45: aload 5 47: invokevirtual #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 50: ldc #12; //String a\nb\nc\nd\n 52: astore 6 54: getstatic #10; //Field java/lang/System.out:Ljava/io/PrintStream; 57: aload 6 59: invokevirtual #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 62: return
为了进一步澄清我的问题,我根本不关心性能。 我关心可维护性和devise问题。
尽可能清楚简单。
我build议使用ThomasPbuild议的实用程序; 然后将其链接到您的构build过程。 包含文本的外部文件仍然存在,但在运行时不读取文件。 工作stream程是:
- build立一个“文本文件到Java代码”的工具和检查到版本控制
- 在每个版本上,对资源文件运行该实用程序以创build修订的Java源代码
- java源代码包含一个
class TextBlock {...
后面跟着一个从资源文件自动生成的静态string - 使用其余的代码构build生成的java文件
一个小窍门。 使用这个我注入javascritp在dynamic创build的HTML页面
StringBuilder builder = new StringBuilder(); public String getString() { return builder.toString(); } private DropdownContent _(String a) { builder.append(a); return this; } public String funct_showhide() { return _("function slidedown_showHide(boxId)"). _("{"). _("if(!slidedown_direction[boxId])slidedown_direction[boxId] = 1;"). _("if(!slideDownInitHeight[boxId])slideDownInitHeight[boxId] = 0;"). _("if(slideDownInitHeight[boxId]==0)slidedown_direction[boxId]=slidedownSpeed; "). _("else slidedown_direction[boxId] = slidedownSpeed*-1;"). _("slidedownContentBox = document.getElementById(boxId);"). _("var subDivs = slidedownContentBox.getElementsByTagName('DIV');"). _("for(var no=0;no<subDivs.length;no++){"). _(" if(subDivs[no].className=='dhtmlgoodies_content')slidedownContent = subDivs[no];"). _("}"). _("contentHeight = slidedownContent.offsetHeight;"). _("slidedownContentBox.style.visibility='visible';"). _("slidedownActive = true;"). _("slidedown_showHide_start(slidedownContentBox,slidedownContent);"). _("}").getString(); }
使用Properties.loadFromXML(InputStream)
。 不需要外部库。
比凌乱的代码更好(因为可维护性和devise是你关心的),最好不要使用长string。
从阅读XML属性开始:
InputStream fileIS = YourClass.class.getResourceAsStream("MultiLine.xml"); Properties prop = new Properies(); prop.loadFromXML(fileIS);
那么你可以使用你的多行string更可维护的方式…
static final String UNIQUE_MEANINGFUL_KEY = "Super Duper UNIQUE Key"; prop.getProperty(UNIQUE_MEANINGFUL_KEY) // "\n MEGA\n LONG\n..."
MultiLine.xml
位于相同的文件夹YourClass:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <entry key="Super Duper UNIQUE Key"> MEGA LONG MULTILINE </entry> </properties>
PS:您可以使用<![CDATA["
… "]]>
作为类似xml的string。
我发现至less有一种情况应该避免在长string中使用外部文件:如果这些长string是unit testing文件中的期望值,因为我认为testing应该总是以不会被写入的方式依靠任何外部资源。
看起来有些疯狂,但是由于heredocs是语法糖,而不是单行声明,并且换行符已经转义,所以可以为Java文件编写预处理程序,在预处理过程中将heredocs转换为单行程。
这将需要编写合适的插件,用于在编译阶段(ant / maven版本)和IDE插件之前对文件进行预处理。
从意识形态的angular度来看,它与“generics”没有任何区别,它也是一种预处理的语法糖而不是铸造。
但是,这是很多工作,所以我会在你的地方使用.properties文件。
Late model JAVA has optimizations for + with constant strings, employs a StringBuffer behind the scenes, so you do not want to clutter your code with it.
It points to a JAVA oversight, that it does not resemble ANSI C in the automatic concatenation of double quoted strings with only white space between them, eg:
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" ;
I would love to have a multi-line character array constant where embedded linefeeds are honored, so I can present the block without any clutter, eg:
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 " ;
To get this, one needs to beat on the JAVA gods.
The only way I know of is to concatenate multiple lines with plus signs