首页 文章

Java多行字符串

提问于
浏览
428

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

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

在Java中,我必须在每一行都有繁琐的引号和加号,因为我从头开始连接多行字符串 .

有哪些更好的选择?在属性文件中定义我的字符串?

Edit :两个答案说StringBuilder.append()优于加号表示法 . 任何人都可以详细说明他们为什么这么认为?它并没有找到解决多线字符串不是一流语言构造这一事实的方法,这意味着我绝对不希望用方法调用替换第一类语言构造(字符串连接加上) .

Edit :为了进一步澄清我的问题,我关注可维护性和设计问题 .

30 回答

  • 17

    在Eclipse中,如果打开选项"Escape text when pasting into a string literal"(在“首选项”>“Java”>“编辑器”>“键入”中)并在引号中粘贴多行字符串,它将自动为所有行添加 "\n" + .

    String str = "paste your text here";
    
  • 2

    在IntelliJ IDE中,您只需键入:

    ""
    

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

  • 9

    您可以使用与java兼容的scala-code,并允许使用“”“括起来的多行字符串:

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

    这是否更舒服......?

    另一种方法,如果你经常处理长文本,它应放在你的源代码中,可能是一个脚本,它从外部文件中获取文本,并将其作为multiline-java-String包装,如下所示:

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

    这样您就可以轻松地将其剪切并粘贴到源中 .

  • 5

    String.join

    Java 8为 java.lang.String 添加了一个新的静态方法,它提供了一个更好的替代方案:

    String.join( CharSequence delimiter , CharSequence... elements )

    使用它:

    String s = String.join(
        System.getProperty("line.separator"),
        "First line.",
        "Second line.",
        "The rest.",
        "And the last!"
    );
    
  • 88

    这是一个旧的线程,但是一个新的非常优雅的解决方案(只有4个小缺点)是使用自定义注释 .

    检查:http://www.adrianwalker.org/2011/12/java-multiline-string.html

    受这项工作启发的项目在GitHub上托管:

    https://github.com/benelog/multiline

    Java代码示例:

    import org.adrianwalker.multilinestring.Multiline;
    ...
    public final class MultilineStringUsage {
    
      /**
      <html>
        <head/>
        <body>
          <p>
            Hello
    Multiline
    World
    </p> </body> </html> */ @Multiline private static String html; public static void main(final String[] args) { System.out.println(html); } }

    缺点是

    • 您必须激活相应的(提供的)注释处理器 .

    • 表示String变量不能定义为局部变量 .

    • 该String不能包含其他变量,如Visual Basic .Net with XML literal( <%= variable %> ):-)

    • 字符串文字由JavaDoc注释(/ **)分隔

    您可能必须将Eclipse / Intellij-Idea配置为不自动重新格式化您的Javadoc注释 .

    有人可能会发现这很奇怪(Javadoc注释并不是为了嵌入除注释之外的其他内容),但由于Java中缺少多行字符串最终会让人烦恼,我发现这是最差的解决方案 .

  • 2

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

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

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

    此解决方案可从以下URL获得... http://www.adrianwalker.org/2011/12/java-multiline-string.html

    希望有所帮助!

  • 45

    我还没有看到答案的另一个选择是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() 方法的事实 .

  • 5

    我知道这是一个老问题,但是对于有兴趣的开发人员来说,多行文字将会出现在#Java12中

    http://mail.openjdk.java.net/pipermail/amber-dev/2018-July/003254.html

  • 2

    听起来你想要做一个多线文字,这在Java中是不存在的 .

    你最好的选择将是一起只是 + 'd的字符串 . 人们提到的其他一些选项(StringBuilder,String.format,String.join)只有在你开始使用字符串数组时才会更好 .

    考虑一下:

    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 .

    另一种选择是将资源放在文本文件中,然后只读取该文件的内容 . 这对于非常大的字符串来说是首选,以避免不必要地膨胀您的类文件 .

  • 6

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

    string:text\u000atext\u000atext\u000a
    

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

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

    如果您有新行,您可能需要一些连接或格式化方法:

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

    如果你像我一样喜欢谷歌的 Guava ,它可以提供一个相当干净的表示和一个很好的,简单的方法来不硬编码您的换行符:

    String out = Joiner.on(newline).join(ImmutableList.of(
        "line1",
        "line2",
        "line3"));
    
  • 38

    将两个字符串转换为StringBuilder.append,除非两个字符串都是常量,因此编译器可以在编译时将它们组合在一起 . 至少,这就是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";
    

    也就是说,在多行中打破你的字符串文字没有任何惩罚,加号为可读性 .

  • 2

    在属性文件中定义我的字符串?

    属性文件中不允许使用多行字符串 . 您可以在属性文件中使用\ n,但我不认为这在您的情况下是一个很大的解决方案 .

  • 9

    使用 Properties.loadFromXML(InputStream) . 不需要外部库 .

    比杂乱的代码更好(因为可维护性和设计是您的关注点),最好不要使用长字符串 . 首先阅读xml属性:

    InputStream fileIS = YourClass.class.getResourceAsStream("MultiLine.xml");
     Properties prop = new Properies();
     prop.loadFromXML(fileIS);
    

    然后你可以 more maintainable 方式使用你的多线字符串...

    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的字符串 .

  • 3

    一个非常有效且独立于平台的解决方案是使用行分隔符的系统属性和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();
    
  • 12

    您可以使用单独的方法连接附加内容,例如:

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

    无论哪种方式,更喜欢 StringBuilder 加号表示法 .

  • 2

    我建议使用ThomasP建议的实用程序,然后将其链接到您的构建过程 . 仍然存在外部文件以包含文本,但在运行时不读取该文件 . 然后工作流程为:

    • 构建'textfile to java code'实用程序并检查版本控制

    • 在每个构建中,针对资源文件运行该实用程序以创建修订的Java源

    • Java源代码包含一个类似 class TextBlock {... 的标头,后跟一个静态字符串,该字符串是从资源文件自动生成的

    • 使用其余代码构建生成的java文件

  • 5

    遗憾的是,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();
    }
    
  • 100

    一个不错的选择 .

    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);
            }
    
        }
    
  • 2

    后期模型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之神 .

  • 181
    String newline = System.getProperty ("line.separator");
    string1 + newline + string2 + newline + string3
    

    但是,最好的选择是使用String.format

    String multilineString = String.format("%s\n%s\n%s\n",line1,line2,line3);
    
  • 10

    一个小技巧 . 使用这个我在动态创建的HTML页面中注入javascritp

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

    当使用很长的一系列时,只创建一个StringBuilder,除非在编译时确定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 .

    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
    

    为了进一步澄清我的问题,我根本不关心表现 . 我担心可维护性和设计问题 .

    尽可能简单明了 .

  • 6
    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");
    
  • 3

    Java Stringfier . 如果需要,将文本转换为StringBuilder java块转义 .

  • 19

    这是你永远不应该使用的东西,而不必考虑它是如何使用它取得巨大成功的:

    例:

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

    Stephen Colebourne创建了一个proposal,用于在Java 7中添加多行字符串 .

    此外,Groovy已经支持multi-line strings .

  • 416

    JEP 326: Raw String Literals将实现多行字符串,因此您可以编写如下内容:

    String s = `
        text
        text
        text
      `;
    

    它被计划为JDK 12中的功能预览 .

  • 9

    另一种选择可能是将长字符串存储在外部文件中并将该文件读入字符串 .

  • 6

    由于Java(尚未)本机支持多行字符串,现在是唯一的方法是使用上述技术之一来破解它 . 我使用上面提到的一些技巧构建了以下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的文件中,并将您的字符串放在mystring.txt文件中,并按如下方式运行:

    cat mystring.txt | python javastringify.py
    

    然后,您可以复制输出并将其粘贴到编辑器中 .

    根据需要修改它以处理任何特殊情况,但这符合我的需要 . 希望这可以帮助!

相关问题