简体   繁体   English

Java 是否支持多行字符串?

[英]Does Java have support for multiline strings?

Coming from Perl, I sure am missing the "here-document" means of creating a multi-line string in source code:来自 Perl,我肯定缺少在源代码中创建多行字符串的“here-document”方法:

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

In Java, I have to have cumbersome quotes and plus signs on every line as I concatenate my multiline string from scratch.在 Java 中,当我从头开始连接多行字符串时,我必须在每一行都有繁琐的引号和加号。

What are some better alternatives?有哪些更好的选择? Define my string in a properties file?在属性文件中定义我的字符串?

Edit : Two answers say StringBuilder.append() is preferable to the plus notation.编辑:两个答案说 StringBuilder.append() 比加号更可取。 Could anyone elaborate as to why they think so?谁能详细说明他们为什么这么认为? It doesn't look more preferable to me at all.它看起来一点也不对我更可取。 I'm looking for a way around the fact that multiline strings are not a first-class language construct, which means I definitely don't want to replace a first-class language construct (string concatenation with plus) with method calls.我正在寻找一种方法来解决多行字符串不是一流的语言构造这一事实,这意味着我绝对不想用方法调用替换一流的语言构造(带加号的字符串连接)。

Edit : To clarify my question further, I'm not concerned about performance at all.编辑:为了进一步澄清我的问题,我根本不关心性能。 I'm concerned about maintainability and design issues.我担心可维护性和设计问题。

It sounds like you want to do a multiline literal, which does not exist in Java.听起来您想要执行 Java 中不存在的多行文字。

Your best alternative is going to be strings that are just + 'd together.你最好的选择将是只是+ 'd 在一起的字符串。 Some other options people have mentioned (StringBuilder, String.format, String.join) would only be preferable if you started with an array of strings.人们提到的其他一些选项(StringBuilder、String.format、String.join)只有在您从字符串数组开始时才更可取。

Consider this:考虑一下:

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";

Versus StringBuilder :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();

Versus String.format() :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"
);

Versus Java8 String.join() :与 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"
);

If you want the newline for your particular system, you either need to use System.lineSeparator() , or you can use %n in String.format .如果您需要特定系统的换行符,则需要使用System.lineSeparator() ,或者您可以在String.format使用%n

Another option is to put the resource in a text file, and just read the contents of that file.另一种选择是将资源放在一个文本文件中,然后读取该文件的内容。 This would be preferable for very large strings to avoid unnecessarily bloating your class files.这对于非常大的字符串是可取的,以避免不必要地膨胀您的类文件。

在 Eclipse 中,如果您打开选项“粘贴到字符串文字时转义文本”(在 Preferences > Java > Editor > Typing 中)并粘贴多行字符串,它会在引号中自动添加"\\n" +你的台词。

String str = "paste your text here";

Stephen Colebourne has created a proposal for adding multi-line strings in Java 7. Stephen Colebourne 提出了在 Java 7 中添加多行字符串的提议

Also, Groovy already has support formulti-line strings .此外,Groovy 已经支持多行字符串

This is an old thread, but a new quite elegant solution (with only 4 maybe 3 little drawbacks) is to use a custom annotation.这是一个旧线程,但一个新的非常优雅的解决方案(只有 4 个也许 3 个小缺点)是使用自定义注释。

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

A project inspired from that work is hosted on GitHub:受该工作启发的项目托管在 GitHub 上:

https://github.com/benelog/multiline https://github.com/benelog/multiline

Example of Java code: Java代码示例:

import org.adrianwalker.multilinestring.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);
  }
}

The drawbacks are缺点是

  1. that you have to activate the corresponding (provided) annotation processor.您必须激活相应的(提供的)注释处理器。
  2. that String variable can not be defined as local variable Check Raw String Literals project where you can define variables as local variables该字符串变量不能定义为局部变量检查原始字符串文字项目,您可以将变量定义为局部变量
  3. that String cannot contains other variables as in Visual Basic .Net with XML literal ( <%= variable %> ) :-)该 String 不能包含其他变量,如 Visual Basic .Net 和 XML 文字( <%= variable %> ):-)
  4. that String literal is delimited by JavaDoc comment (/**)该字符串文字由 JavaDoc 注释 (/**) 分隔

And you probably have to configure Eclipse/Intellij-Idea to not reformat automatically your Javadoc comments.并且您可能必须配置 Eclipse/Intellij-Idea 以不自动重新格式化您的 Javadoc 注释。

One may find this weird (Javadoc comments are not designed to embed anything other than comments), but as this lack of multiline string in Java is really annoying in the end, I find this to be the least worst solution.人们可能会觉得这很奇怪(Javadoc 注释并非旨在嵌入除注释以外的任何内容),但由于 Java 中缺少多行字符串最终真的很烦人,我发现这是最不糟糕的解决方案。

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

This is something that you should never use without thinking about what it's doing.这是你永远不应该在不考虑它在做什么的情况下使用的东西。 But for one-off scripts I've used this with great success:但是对于一次性脚本,我已经非常成功地使用了它:

Example:例子:

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

Code:代码:

// 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 added a new static method to java.lang.String which offers a slightly better alternative: Java 8 向java.lang.String添加了一个新的静态方法,它提供了一个更好的替代方法:

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

Using it:使用它:

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

JEP 378: Text Blocks covers this functionality and is included in JDK 15. It first appeared as JEP 355: Text Blocks (Preview) in JDK 13 and JEP 368: Text Blocks (Second Preview) in JDK 14 and can be enabled in these versions with the ––enable–preview javac option. JEP 378:Text Blocks涵盖了此功能,并包含在 JDK 15 中。它首先作为JEP 355: JDK 13 中的文本块(预览版)JEP 368: JDK 14 中的文本块(第二版预览版)出现,并且可以在这些版本中启用使用––enable–preview javac 选项。

The syntax allows to write something like:语法允许编写如下内容:

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

Previous to this JEP, in JDK 12, JEP 326: Raw String Literals aimed to implement a similar feature, but it was eventually withdrawn:在此 JEP 之前,在 JDK 12 中, JEP 326:Raw String Literals旨在实现类似的功能,但最终被撤回:

Please note: This was intended to be a preview language feature in JDK 12, but it was withdrawn and did not appear in JDK 12. It was superseded by Text Blocks ( JEP 355 ) in JDK 13.请注意:这原本是 JDK 12 中的一个预览语言功能,但它被撤回并且没有出现在 JDK 12 中。它被 JDK 13 中的文本块 ( JEP 355 ) 取代。

Java 13 and beyond Java 13 及更高版本

Multiline Strings are now supported in Java via Text Blocks . Java 现在通过Text Blocks支持多行字符串。 In Java 13 and 14, this feature requires you to set the ––enable–preview option when building and running your project.在 Java 13 和 14 中,此功能要求您在构建和运行项目时设置––enable–preview选项。 In Java 15 and later, this option is no longer required as Text Blocks have become a standard feature.在 Java 15 及更高版本中,不再需要此选项,因为文本块已成为标准功能。 Check out the official Programmer's Guide to Text Blocks for more details.查看官方的文本块程序员指南以获取更多详细信息。

Now, prior to Java 13, this is how you'd write a query:现在,在 Java 13 之前,这是您编写查询的方式:

List<Tuple> posts = entityManager
.createNativeQuery(
    "SELECT *\n" +
    "FROM (\n" +
    "    SELECT *,\n" +
    "           dense_rank() OVER (\n" +
    "               ORDER BY \"p.created_on\", \"p.id\"\n" +
    "           ) rank\n" +
    "    FROM (\n" +
    "        SELECT p.id AS \"p.id\",\n" +
    "               p.created_on AS \"p.created_on\",\n" +
    "               p.title AS \"p.title\",\n" +
    "               pc.id as \"pc.id\",\n" +
    "               pc.created_on AS \"pc.created_on\",\n" +
    "               pc.review AS \"pc.review\",\n" +
    "               pc.post_id AS \"pc.post_id\"\n" +
    "        FROM post p\n" +
    "        LEFT JOIN post_comment pc ON p.id = pc.post_id\n" +
    "        WHERE p.title LIKE :titlePattern\n" +
    "        ORDER BY p.created_on\n" +
    "    ) p_pc\n" +
    ") p_pc_r\n" +
    "WHERE p_pc_r.rank <= :rank\n",
    Tuple.class)
.setParameter("titlePattern", "High-Performance Java Persistence %")
.setParameter("rank", 5)
.getResultList();

Thanks to Java 13 Text Blocks, you can rewrite this query as follows:感谢 Java 13 文本块,您可以按如下方式重写此查询:

List<Tuple> posts = entityManager
.createNativeQuery("""
    SELECT *
    FROM (
        SELECT *,
               dense_rank() OVER (
                   ORDER BY "p.created_on", "p.id"
               ) rank
        FROM (
            SELECT p.id AS "p.id",
                   p.created_on AS "p.created_on",
                   p.title AS "p.title",
                   pc.id as "pc.id",
                   pc.created_on AS "pc.created_on",
                   pc.review AS "pc.review",
                   pc.post_id AS "pc.post_id"
            FROM post p
            LEFT JOIN post_comment pc ON p.id = pc.post_id
            WHERE p.title LIKE :titlePattern
            ORDER BY p.created_on
        ) p_pc
    ) p_pc_r
    WHERE p_pc_r.rank <= :rank
    """,
    Tuple.class)
.setParameter("titlePattern", "High-Performance Java Persistence %")
.setParameter("rank", 5)
.getResultList();

Much more readable, right?更具可读性,对吧?

IDE support IDE支持

IntelliJ IDEA provides support for transforming legacy String concatenation blocks to the new multiline String format: IntelliJ IDEA 支持将旧的String连接块转换为新的多行String格式:

IntelliJ IDEA 文本块支持

JSON, HTML, XML JSON、HTML、XML

The multiline String is especially useful when writing JSON, HTML, or XML.多行String在编写 JSON、HTML 或 XML 时特别有用。

Consider this example using String concatenation to build a JSON string literal:考虑这个使用String连接来构建 JSON 字符串文字的示例:

entityManager.persist(
    new Book()
    .setId(1L)
    .setIsbn("978-9730228236")
    .setProperties(
        "{" +
        "   \"title\": \"High-Performance Java Persistence\"," +
        "   \"author\": \"Vlad Mihalcea\"," +
        "   \"publisher\": \"Amazon\"," +
        "   \"price\": 44.99," +
        "   \"reviews\": [" +
        "       {" +
        "           \"reviewer\": \"Cristiano\", " +
        "           \"review\": \"Excellent book to understand Java Persistence\", " +
        "           \"date\": \"2017-11-14\", " +
        "           \"rating\": 5" +
        "       }," +
        "       {" +
        "           \"reviewer\": \"T.W\", " +
        "           \"review\": \"The best JPA ORM book out there\", " +
        "           \"date\": \"2019-01-27\", " +
        "           \"rating\": 5" +
        "       }," +
        "       {" +
        "           \"reviewer\": \"Shaikh\", " +
        "           \"review\": \"The most informative book\", " +
        "           \"date\": \"2016-12-24\", " +
        "           \"rating\": 4" +
        "       }" +
        "   ]" +
        "}"
    )
);

You can barely read the JSON due to the escaping characters and the abundance of double quotes and plus signs.由于转义字符以及大量双引号和加号,您几乎无法读取 JSON。

With Java Text Blocks, the JSON object can be written like this:使用 Java 文本块,JSON 对象可以这样编写:

entityManager.persist(
    new Book()
    .setId(1L)
    .setIsbn("978-9730228236")
    .setProperties("""
        {
           "title": "High-Performance Java Persistence",
           "author": "Vlad Mihalcea",
           "publisher": "Amazon",
           "price": 44.99,
           "reviews": [
               {
                   "reviewer": "Cristiano",
                   "review": "Excellent book to understand Java Persistence",
                   "date": "2017-11-14",
                   "rating": 5
               },
               {
                   "reviewer": "T.W",
                   "review": "The best JPA ORM book out there",
                   "date": "2019-01-27",
                   "rating": 5
               },
               {
                   "reviewer": "Shaikh",
                   "review": "The most informative book",
                   "date": "2016-12-24",
                   "rating": 4
               }
           ]
        }
        """
    )
);

Ever since I used C# in 2004, I've been wanting to have this feature in Java, and now we finally have it.自从我在 2004 年使用 C# 以来,我一直想在 Java 中拥有这个功能,现在我们终于有了它。

If you define your strings in a properties file it'll look much worse.如果你在属性文件中定义你的字符串,它看起来会更糟。 IIRC, it'll look like: IIRC,它看起来像:

string:text\u000atext\u000atext\u000a

Generally it's a reasonable idea to not embed large strings in to source.通常,不将大字符串嵌入到源代码中是一个合理的想法。 You might want to load them as resources, perhaps in XML or a readable text format.您可能希望将它们作为资源加载,可能是 XML 或可读的文本格式。 The text files can be either read at runtime or compiled into Java source.文本文件可以在运行时读取或编译为 Java 源代码。 If you end up placing them in the source, I suggest putting the + at the front and omitting unnecessary new lines:如果您最终将它们放在源代码中,我建议将+放在前面并省略不必要的新行:

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

If you do have new lines, you might want some of join or formatting method:如果您确实有新行,您可能需要一些连接或格式化方法:

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

In the IntelliJ IDE you just need to type:在 IntelliJ IDE 中,您只需键入:

""

Then position your cursor inside the quotation marks and paste your string.然后将光标放在引号内并粘贴您的字符串。 The IDE will expand it into multiple concatenated lines. IDE 会将其扩展为多条连接线。

Pluses are converted to StringBuilder.append, except when both strings are constants so the compiler can combine them at compile time.加号被转换为 StringBuilder.append,除非两个字符串都是常量,因此编译器可以在编译时组合它们。 At least, that's how it is in Sun's compiler, and I would suspect most if not all other compilers would do the same.至少,Sun 的编译器就是这样,我怀疑大多数(如果不是所有)其他编译器也会这样做。

So:所以:

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

normally generates exactly the same code as:通常生成与以下完全相同的代码:

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

On the other hand:另一方面:

String c="Hello"+"Goodbye";

is the same as:是相同的:

String c="HelloGoodbye";

That is, there's no penalty in breaking your string literals across multiple lines with plus signs for readability.也就是说,为了可读性,用加号将字符串文字分成多行不会有任何损失。

Sadly, Java does not have multi-line string literals.遗憾的是,Java 没有多行字符串文字。 You either have to concatenate string literals (using + or StringBuilder being the two most common approaches to this) or read the string in from a separate file.您要么必须连接字符串文字(使用 + 或 StringBuilder 是两种最常见的方法),要么从单独的文件中读取字符串。

For large multi-line string literals I'd be inclined to use a separate file and read it in using getResourceAsStream() (a method of the Class class).对于大型多行字符串文字,我倾向于使用单独的文件并使用getResourceAsStream()Class类的方法getResourceAsStream()读取它。 This makes it easy to find the file as you don't have to worry about the current directory versus where your code was installed.这使得查找文件变得容易,因为您不必担心当前目录与安装代码的位置。 It also makes packaging easier, because you can actually store the file in your jar file.它还使打包更容易,因为您实际上可以将文件存储在 jar 文件中。

Suppose you're in a class called Foo.假设您在一个名为 Foo 的类中。 Just do something like this:只是做这样的事情:

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

The one other annoyance is that Java doesn't have a standard "read all of the text from this Reader into a String" method.另一个烦恼是 Java 没有标准的“将来自该 Reader 的所有文本读入字符串”方法。 It's pretty easy to write though:不过写起来很简单:

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();
}
String newline = System.getProperty ("line.separator");
string1 + newline + string2 + newline + string3

But, the best alternative is to use String.format但是,最好的选择是使用String.format

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

You may use scala-code, which is compatible to java, and allows multiline-Strings enclosed with """:您可以使用与 java 兼容的 Scala 代码,并允许用 """ 括起来的多行字符串:

package foobar
object SWrap {
  def bar = """John said: "This is
  a test
  a bloody test,
  my dear." and closed the door.""" 
}

(note the quotes inside the string) and from java: (注意字符串内的引号)和来自 java:

String s2 = foobar.SWrap.bar ();

Whether this is more comfortable ...?这是否更舒服......?

Another approach, if you often handle long text, which should be placed in your sourcecode, might be a script, which takes the text from an external file, and wrappes it as a multiline-java-String like this:另一种方法,如果您经常处理应该放在源代码中的长文本,则可能是一个脚本,它从外部文件中获取文本,并将其包装为多行 java-String,如下所示:

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

so that you may cut-and-paste it easily into your source.以便您可以轻松地将其剪切并粘贴到源中。

Since Java does not (yet) native support multi-line strings, the only way for now is to hack around it using one of the aforementioned techniques.由于 Java 不(还)本机支持多行字符串,目前唯一的方法是使用上述技术之一绕过它。 I built the following Python script using some of the tricks mentioned above:我使用上面提到的一些技巧构建了以下 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 ')'

Put that in a file named javastringify.py and your string in a file mystring.txt and run it as follows:把它放在一个名为 javastringify.py 的文件中,并将你的字符串放在文件 mystring.txt 中,然后按如下方式运行它:

cat mystring.txt | python javastringify.py

You can then copy the output and paste it into your editor.然后,您可以复制输出并将其粘贴到您的编辑器中。

Modify this as needed to handle any special cases but this works for my needs.根据需要修改它以处理任何特殊情况,但这适合我的需要。 Hope this helps!希望这可以帮助!

You can concatenate your appends in a separate method like:您可以使用单独的方法连接附加内容,例如:

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

Either way, prefer StringBuilder to the plus notation.无论哪种方式,都更喜欢StringBuilder而不是加号。

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

Actually, the following is the cleanest implementation I have seen so far.实际上,以下是迄今为止我见过的最干净的实现。 It uses an annotation to convert a comment into a string variable...它使用注释将注释转换为字符串变量...

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

So, the end result is that the variable html contains the multiline string.因此,最终结果是变量 html 包含多行字符串。 No quotes, no pluses, no commas, just pure string.没有引号,没有加号,没有逗号,只有纯字符串。

This solution is available at the following URL... http://www.adrianwalker.org/2011/12/java-multiline-string.html此解决方案可在以下 URL... http://www.adrianwalker.org/2011/12/java-multiline-string.html

Hope that helps!希望有帮助!

See Java Stringfier .请参阅Java Stringfier Turns your text into a StringBuilder java block escaping if needed.如果需要,将您的文本转换为 StringBuilder java 块进行转义。

An alternative I haven't seen as answer yet is the java.io.PrintWriter .我还没有看到答案的另一种java.io.PrintWriterjava.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();

Also the fact that java.io.BufferedWriter has a newLine() method is unmentioned.也没有提到java.io.BufferedWriter有一个newLine()方法的事实。

If you like google's guava as much as I do, it can give a fairly clean representation and a nice, easy way to not hardcode your newline characters too:如果你和我一样喜欢谷歌的番石榴,它可以提供一个相当干净的表示和一个很好的、简单的方法来不硬编码你的换行符:

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

Use Properties.loadFromXML(InputStream) .使用Properties.loadFromXML(InputStream) There's no need for external libs.不需要外部库。

Better than a messy code (since maintainability and design are your concern), it is preferable not to use long strings.比凌乱的代码更好(因为可维护性和设计是您关心的问题),最好不要使用长字符串。

Start by reading xml properties:首先阅读 xml 属性:

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


then you can use your multiline string in a more maintainable way...那么你可以以更易于维护的方式使用你的多行字符串......

static final String UNIQUE_MEANINGFUL_KEY = "Super Duper UNIQUE Key";
prop.getProperty(UNIQUE_MEANINGFUL_KEY) // "\n    MEGA\n   LONG\n..."


MultiLine.xml` gets located in the same folder YourClass: 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.: You can use <![CDATA[" ... "]]> for xml-like string. PS.:您可以使用<![CDATA[" ... "]]>作为类似 xml 的字符串。

With JDK/12 early access build # 12 , one can now use multiline strings in Java as follows :使用JDK/12 早期访问版本 #12 ,现在可以在 Java 中使用多行字符串,如下所示:

String multiLine = `First line
    Second line with indentation
Third line
and so on...`; // the formatting as desired
System.out.println(multiLine);

and this results in the following output:这导致以下输出:

 First line Second line with indentation Third line and so on...

Edit: Postponed to java 13编辑:推迟到 java 13

Java 13 preview: Java 13 预览版:

Text Blocks Come to Java. 文本块来到 Java。 Java 13 delivers long-awaited multiline string by Mala Gupta Java 13 提供了 Mala Gupta 期待已久的多行字符串

With text blocks, Java 13 is making it easier for you to work with multiline string literals.通过文本块,Java 13 使您可以更轻松地处理多行字符串文字。 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.文本块使用三个双引号 (""") 作为开始和结束分隔符来定义。开始分隔符后面可以跟零个或多个空格和一个行终止符。

Example:例子:

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

One good option.一个不错的选择。

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

    }

A quite efficient and platform independent solution would be using the system property for line separators and the StringBuilder class to build strings:一个非常有效且与平台无关的解决方案是使用系统属性作为行分隔符和 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();

I suggest using a utility as suggested by ThomasP, and then link that into your build process.我建议使用 ThomasP 建议的实用程序,然后将其链接到您的构建过程中。 An external file is still present to contain the text, but the file is not read at runtime.仍然存在包含文本的外部文件,但不会在运行时读取该文件。 The workflow is then:然后工作流程是:

  1. Build a 'textfile to java code' utility & check into version control构建“文本文件到 Java 代码”实用程序并检查版本控制
  2. On each build, run the utility against the resource file to create a revised java source在每次构建时,针对资源文件运行该实用程序以创建修改后的 java 源
  3. The Java source contains a header like class TextBlock {... followed by a static string which is auto-generated from the resource file Java 源代码包含一个像class TextBlock {...这样的标头class TextBlock {...后跟一个从资源文件自动生成的静态字符串
  4. Build the generated java file with the rest of your code使用其余代码构建生成的 java 文件

I know this is an old question, however for intersted developers Multi line literals gonna be in #Java12我知道这是一个老问题,但是对于有兴趣的开发人员来说,多行文字将出现在 #Java12 中

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

Define my string in a properties file?在属性文件中定义我的字符串?

Multiline strings aren't allowed in properties files.属性文件中不允许使用多行字符串。 You can use \\n in properties files, but I don't think that is much of a solution in your case.您可以在属性文件中使用 \\n ,但我认为这不是您的解决方案。

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.后期模型 JAVA 对 + 使用常量字符串进行了优化,在幕后使用了 StringBuffer,因此您不想用它来弄乱您的代码。

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:它指出了 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" ;

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.要得到这个,需要打败 JAVA 诸神。

One small trick. 一个小把戏。 Using this I inject javascritp in a dynamically created HTML page 使用此方法,我将javascritp注入动态创建的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();

}

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

When a long series of + are used, only one StringBuilder is created, unless the String is determined at compile time in which case no StringBuilder is used! 当使用一连串的+时,除非在编译时确定String的情况下,否则仅创建一个StringBuilder,在这种情况下,不使用StringBuilder!

The only time StringBuilder is more efficient is when multiple statements are used to construct the String. 只有使用多个语句来构造String时,StringBuilder才更有效率。

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

Note: Only one StringBuilder is created. 注意:仅创建一个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

To clarify my question further, I'm not concerned about performance at all. 为了进一步阐明我的问题,我根本不关心性能。 I'm concerned about maintainability and design issues. 我担心可维护性和设计问题。

Make it as clear and simple as you can. 使其尽可能简单明了。

It may seem a little crazy, but since heredocs are syntactic sugar over one-line declarations with linebreaks escaped, one could write pre-processor for Java files that would change heredocs into single-liners during preprocessing.这可能看起来有点疯狂,但是由于heredocs 是单行声明的语法糖,换行符被转义,因此可以为Java 文件编写预处理器,在预处理期间将heredocs 更改为单行。

It would require writing proper plugins for preprocessing files before compilation phase (for ant/maven build) and a plugin to IDE.它需要在编译阶段(用于 ant/maven 构建)和 IDE 插件之前为预处理文件编写适当的插件。

From an ideological point of view, it differs nothing from fg "generics", that is also a kind of pre-processed syntactic sugar over casting.从思想上看,它与 fg "generics" 没有什么不同,它也是一种预处理的语法糖 over cast。

It's, however, a lot of work, so I would at your place just use .properties files.然而,这是大量的工作,所以我会在你的地方只使用 .properties 文件。

I sometimes use a parallel groovy class just to act as a bag of strings我有时会使用并行的 groovy 类来充当一袋字符串

The java class here这里的java类

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

And the coveted multiline strings here in TestStrings.groovy以及 TestStrings.groovy 中令人垂涎的多行字符串

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

Of course this is for static strings only.当然,这仅适用于静态字符串。 If I have to insert variables in the text I will just change the entire file to groovy.如果我必须在文本中插入变量,我只会将整个文件更改为 groovy。 Just maintain strong-typing practices and it can be pulled off.只需保持强类型实践,它就可以被拉下来。

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

Using this library使用这个库

https://github.com/alessio-santacroce/multiline-string-literals https://github.com/alessio-santacroce/multiline-string-literals

it is possible to write things like this可以写这样的东西

System.out.println(newString(/*
      Wow, we finally have
      multiline strings in
      Java! HOOO!
*/));

Very nice and easy, but works only for unit tests非常好且简单,但仅适用于单元测试

Two answers to this question:这个问题的两个答案:

  1. 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.如果您想坚持使用纯 Java,Java 14 将于 2020 年 3 月发布,您可以在第二预览模式下利用JEP 368 - 文本块。 Actually the feature is in preview mode in other releases (at least 13 has it).实际上,该功能在其他版本中处于预览模式(至少有 13 个版本)。 I created and example set here .我在这里创建并设置示例。
  2. 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).请记住,Java 需要编译 - 在您的代码中使用大型字符数组可能是一种让自己陷入困境的简单方法(如果您想要快速更改,则需要重新编译 - 操作您的应用程序的人可能无法使用该工具集) .

In my experience, it is advisable to keep large strings (and generally strings that could/should be altered at runtime by app operators) in configuration files.根据我的经验,建议在配置文件中保留大字符串(通常是应用操作员可以/应该在运行时更改的字符串)。

Summary: use text blocks responsibly :).总结:负责任地使用文本块:)。

我知道的唯一方法是用加号连接多行

A simple option is to edit your java-code with an editor like SciTE ( http://www.scintilla.org/SciTEDownload.html ), which allows you to WRAP the text so that long strings are easily viewed and edited.一个简单的选择是使用像 SciTE ( http://www.scintilla.org/SciTEDownload.html ) 这样的编辑器来编辑您的 java 代码,它允许您包装文本,以便轻松查看和编辑长字符串。 If you need escape characters you just put them in. By flipping the wrap-option off you can check that your string indeed is still just a long single-line string.如果您需要转义字符,您只需将它们放入。通过关闭换行选项,您可以检查您的字符串确实仍然只是一个长的单行字符串。 But of course, the compiler will tell you too if it isn't.但当然,如果不是,编译器也会告诉你。

Whether Eclipse or NetBeans support text-wrapping in an editor I don't know, because they have so many options.我不知道 Eclipse 或 NetBeans 是否支持编辑器中的文本换行,因为它们有很多选项。 But if not, that would be a good thing to add.但如果没有,那将是一件好事。

I got a bit annoyed with reading that multiline syntax is indeed been planned for jdk7 (after about how many decades of java existence?).读到多行语法确实是为 jdk7 计划的(在 Java 存在了大约多少年之后?),我有点恼火。 Funnily, there is not even yet a readAll() function for reading the complete contents of a file (from jdk7 only, huhh), so the code below reads single lines.有趣的是,甚至还没有 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);
    }
  }
}

This was the quickest solution for me.这对我来说是最快的解决方案。 (2010-01-27) (2010-01-27)

It's not entirely clear from the question if author is interested in working with some sort of formatted large strings that need to have some dynamic values, but if that's the case a templating engine like StringTemplate ( http://www.stringtemplate.org/ ) might be very useful.从问题中并不完全清楚作者是否有兴趣使用某种需要具有一些动态值的格式化大字符串,但如果是这种情况,则使用像 StringTemplate ( http://www.stringtemplate.org/ ) 这样的模板引擎可能非常有用。

A simple sample of the code that uses StringTemplate is below.下面是使用 StringTemplate 的简单代码示例。 The actual template ("Hello, < name >") could be loaded from an external plain text file.实际模板(“Hello, < name >”)可以从外部纯文本文件加载。 All indentation in the template will be preserved, and no escaping is necessary.模板中的所有缩进都将被保留,不需要转义。

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

PS It's always a good idea to remove large chunks of text from source code for readability and localization purposes. PS 出于可读性和本地化目的,从源代码中删除大块文本总是一个好主意。

You can use Kotlin multiple line string support..您可以使用 Kotlin 多行字符串支持..

Just Create a Kotlin class, and use it there,只需创建一个 Kotlin 类,并在那里使用它,

You can call kotlin class as java synxtax您可以将 kotlin 类称为 java 语法

//Kotlin //科特林

    fun jsIncreaseOrDecreaseWebFonts(webView : YHYWebView, sliderValue : Int, intFontSize : Int){
            var initialData = """
                  bla bla
                """

}

//From Java //来自Java

 KotlinFunctions t = new KotlinFunctions();
 t.jsIncreaseOrDecreaseWebFonts(webView,progresValue,incOrDec);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM