621

Coming from Perl, I sure am missing the "here-document" means of creating a multi-line string in source code:

$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.

What are some better alternatives? Define my string in a properties file?

Edit: Two answers say StringBuilder.append() is preferable to the plus notation. 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.

2240
  • 1,547
  • 2
  • 12
  • 30
skiphoppy
  • 97,646
  • 72
  • 174
  • 218
  • 13
    StringBuilder.append() is preferable to plus when repeatedly adding to a string because every time you do `string1 + string2` you're allocating a new string object and copying the characters from both of the input strings. If you're adding n Strings together you'd be doing n-1 allocations and approximately (n^2)/2 character copies. StringBuilder, on the other hand, copies and reallocates less frequently (though it still does both when you exceed the size of its internal buffer). Theoretically, there are cases where the compiler could convert + to use StringBuilder but in practice who knows. – Laurence Gonsalves May 18 '09 at 17:18
  • 1
    Oops. That part abut the character copies was a bit confused/unclear. Each character gets copied once for every string that comes after it in the concatenation. If all of your strings are one character you get roughly (n^2)/2 character copies. It's really sort of (n^2)/2 string copies, except the later times a string is copied it's copied along with the stuff it's been joined to (but the cost is proprotional to the number of characters, so counting string copies is a bit misleading). Long story short: the cost is roughly quadratic, while StringBuilder tries to make the amortized cost linear. – Laurence Gonsalves May 18 '09 at 17:26
  • There's an article on this topic -- I've added a link below, but here it is again: http://java.sun.com/developer/JDCTechTips/2002/tt0305.html – Paul Morie May 18 '09 at 17:33
  • 5
    Every time I jump into the debugger, + is converted to a StringBuilder.append() call, on Java 1.5. I've had colleagues confusedly tell me StringBuilder has a bug since they debug into code that does not appear to call it and wind up there. – skiphoppy May 18 '09 at 17:34
  • 4
    See also: http://stackoverflow.com/questions/782810/working-with-large-text-snippets-in-java-source – Michael Myers May 18 '09 at 17:55
  • 66
    Note that a string literal made up of "abc\n" + "def\n" etc. does not use StringBuilder: the compiler glues them together and puts them into the .class file as a single literal, same as with other types of constant folding. – araqnid May 18 '09 at 18:00
  • 7
    Most IDEs support entering multi-line strings. ie. you just type or paste what you want into a "" string and it will add the \n and " + " as required. e.g. I can paste a 40 lines of text into a String and teh IDE sorts it out for you. – Peter Lawrey Oct 24 '10 at 12:19
  • @Laurence Gonsalves: That's what I learned in school, but recently I checked the bytecode that was compiled from my concatenating multiple strings, and it used `StringBuilder`. This was with the Eclipse compiler, I don't know about `javac`. – Bart van Heukelom Dec 14 '10 at 12:03
  • @Bart van Heukelom: that's why I said "but in practice who knows". Never Java compiler (including recent versions if `javac`, I believe) do attempt some optimization here and will use `StringBuilder` in the implementation of `+` in certain cases. Last time I checked those cases were pretty simple, however, so it's pretty easy to have code that uses `+` and is compiling to something efficient that suddenly becomes quadratic because of a seemingly minor change to the source. Unless all of your `+`'s are in a single expression, I'd use `StringBuilder` instead. – Laurence Gonsalves Dec 14 '10 at 17:15
  • 2
    To repeat araqnid, who seems to have gotten buried, given how many replies recommend StringBuilder: adjacent literals are concatenated by the compiler. Note that that's only if you use +. For +=, you get a StringBuilder. I'd even say that using StringBuilder outside of a loop is a little OCD. – johncip May 09 '11 at 07:38
  • [This answer](http://stackoverflow.com/a/121513/403455) shows how to paste multi-line escaped strings in Eclispe. – Jeff Axelrod Mar 09 '12 at 18:41
  • 1
    I believe what @Laurence said is wrong: even don't consider compiler joining literal become one, "a" + "b" + "c" + "d" does NOT generate 3 extra string. It is a defined behavior that the above code is generated to `new StringBuilder().append("a").append("b").append("c").append("d").toString()` (or StringBuffer with JDK < 1.5). Therefore, in such case, never use StringBuffer/StringBuilder as it is not helping anything – Adrian Shum Jul 20 '12 at 10:08
  • 1
    @AdrianShum can you point to the spec that defines the behavior you describe? Also note that I said "Unless all of your `+`'s are in a single expression...", and in your example all of them are in a single expression. – Laurence Gonsalves Jul 20 '12 at 23:29
  • @LaurenceGonsalves After a brief search I found JLS seems didn't put what I said as the spec, but the behavior is what JDK implemented (I doubt if any other JDK is having big difference on that). I also noted your "..in a single expression" line but your first few comment did give an impression that same holds to an expression with multiple concat and your "..in a single expression" statement didn't clarify yet, that's why I state the behavior just to avoid confusion or misunderstanding on JDK's behavior. – Adrian Shum Jul 23 '12 at 01:44
  • 1
    I have decided to use http://stackoverflow.com/questions/12115115/java-annotation-utility-for-multiline-text. Superb and elegant. – Blessed Geek Sep 27 '12 at 16:54
  • possible duplicate of [Paste a multi-line Java String in Eclipse](http://stackoverflow.com/questions/2159678/paste-a-multi-line-java-string-in-eclipse) – Tomasz Apr 01 '14 at 19:33
  • 3
    This is bad part of Java/Oracle, comparing to C#/MS, perl etc.... – Herbert Yu May 07 '15 at 21:09
  • It finally makes it into Java 12. "Raw String Literals". There's decent blog post here: https://www.vojtechruzicka.com/raw-strings/ – JGFMK Nov 06 '19 at 12:44
  • This issue with java is the one that finally compelled me to get a jvm language. Incredibly frustrating to build a test program or a configuration routine without this feature. Fortunately `scala` had just come of age at that time (2013). Now i'm forced to use java again and so the desperation returns (can't depend on having recent versions of java available) – WestCoastProjects Jan 06 '20 at 01:22
  • Oh and `raw string literals` STILL do not exist even in Java13. Instead they're `text blocks` that are *not* the same . They do not allow pure raw unfiltered strings and also do not support interpolation. – WestCoastProjects Jan 06 '20 at 01:23

43 Answers43

563

NOTE: This answer applies to Java 14 and older.

Text blocks (multiline literals) were introduced in Java 15. See this answer for details.


It sounds like you want to do a multiline literal, which does not exist in Java.

Your best alternative is going to be strings that are just +'d together. Some other options people have mentioned (StringBuilder, String.format, String.join) would only be preferable if you started with an array of strings.

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:

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

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.

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.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Kip
  • 107,154
  • 87
  • 232
  • 265
  • 268
    Furthermore, the first version will be automatically concatenated by the compiler, since all the strings are known at compile time. Even if the strings are not known at compile time, it's no slower than StringBuilder or String.format(). The only reason to avoid concatenation with +'s is if you're doing it in a loop. – Michael Myers May 18 '09 at 17:06
  • The StringBuilder is what I've seen (again and again) as the maintainable and efficient code. The String.format is efficient, but uncommon enough for Java developers that the maintainability drops. – Dean J May 17 '10 at 15:01
  • 27
    The problem with the `String.format` version is that you have to keep the format in sync with the number of lines. – Bart van Heukelom Dec 14 '10 at 12:05
  • 6
    String.format is not efficient compared to other two examples – cmcginty Dec 30 '10 at 00:50
  • 1
    @MichaelMyers Another reason to avoid concatenation with +'s is it looks so terrible and is much harder to maintain than options that are present in other languages. :) – skiphoppy Sep 05 '12 at 17:46
  • 12
    This answer is a very inappropriate solution to the question at hand. We have 2000 line SAS macros or bunches of 200 line SQL queries which we wish to copy and paste. To suggest that we use +"" concat to transform those multiline text into StringBuffer appends is ridiculous. – Blessed Geek Sep 24 '12 at 19:44
  • 25
    @BlessedGeek: the question at hand was about what options were available in the Java language. It didn't mention anything about the type of data going into the string. If there is a better solution then you can post it as an answer. It sounds like [Josh Curren's solution](http://stackoverflow.com/a/878603/18511) would be better for your situation. If you are just upset that the language doesn't support multiline literals then this is the wrong place to complain about it. – Kip Sep 24 '12 at 20:08
  • 2
    Having used Perl, I understand the asker's requirement. What are the various alternatives to allowing multiline string without having to mess it up with + signs and quotation. I used adrianwalker's annotation. Using concat is not an alternative to multiline string. – Blessed Geek Sep 27 '12 at 16:52
  • 2
    I have used the `String+` version for sometime (after learning that at compile time it is turned into a single string), but I always had the `+` at the end of each line. Seeing it with the `+` aligned with the `=` looks a lot cleaner. – Jason Sperske Apr 29 '13 at 16:56
  • 2
    @BlessedGeek if you are coming to java from another background, you may very well wonder if java provides this functionality. just because the answer is "no" doesn't mean that the answer is obvious – Kip Jul 17 '14 at 19:24
  • 2
    Even more startling than the lack of multi-line string literal support is the lack of a `StringBuilder.appendLine()` function that takes care of the `System.getProperty("line.separator")` for you... – Patrick M Sep 12 '14 at 15:16
  • 5
    @TudorManole: Each time you use the `+` operator on Strings (not counting string constants) the compiler turns that into a three-step process: (1) creating a new StringBuilder object, (2) appending both Strings to it, and (3) using toString() to turn it back into a String. That is not something you want to do inside a loop. If you need a loop, you generally want to set up a single StringBuilder first and then append() to it inside the loop. That way there's just the one object and it doesn't do all that extra copying. See https://stackoverflow.com/a/7819127 for a slightly longer version. – Michael Myers Jul 29 '15 at 23:19
  • 1
    I agree. If you come from a world where here-scripts are possible, this lack in Java is very tedious. – Thorbjørn Ravn Andersen Oct 05 '15 at 15:58
  • Support for multiline string literals (text blocks) was introduced in Java 15 with [JEP 378: Text Blocks](https://openjdk.java.net/jeps/378). – Mark Rotteveel Dec 22 '21 at 13:54
193

In Eclipse if you turn on the option "Escape text when pasting into a string literal" (in Preferences > Java > Editor > Typing) and paste a multi-lined string whithin quotes, it will automatically add " and \n" + for all your lines.

String str = "paste your text here";
bluish
  • 26,356
  • 27
  • 122
  • 180
Monir
  • 840
  • 1
  • 10
  • 27
123

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.

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:

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.

M. Justin
  • 14,487
  • 7
  • 91
  • 130
alostale
  • 770
  • 1
  • 11
  • 21
  • 1
    Oracle also issued some guidance which is a more practical reference than the JEPs: https://docs.oracle.com/en/java/javase/15/text-blocks/index.html – Luke Usherwood Dec 07 '21 at 18:25
102

This is an old thread, but a new quite elegant solution (with only 4 maybe 3 little drawbacks) is to use a custom annotation.

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

A project inspired from that work is hosted on GitHub:

https://github.com/benelog/multiline

Example of Java code:

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 %>) :-)
  4. that String literal is delimited by JavaDoc comment (/**)

And you probably have to configure Eclipse/Intellij-Idea to not reformat automatically your Javadoc comments.

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.

deFreitas
  • 4,196
  • 2
  • 33
  • 43
SRG
  • 1,569
  • 1
  • 17
  • 19
  • Does that require the class using the multiline string to be final? Also, is any setup required when developing and executing code from Eclipse? The reference URL mentions setup requirements for Maven for annotation processing. I can't figure out what might be needed, if any in Eclipse. – David May 17 '13 at 21:55
  • The annotation is livable - but it seems there were also a hard dependency on maven? That part takes away much of the value of heredoc's which are to simplify the management of small pieces of text. – WestCoastProjects May 28 '13 at 00:23
  • 3
    You can do this entirely in eclipse. The link that @SRG posted above points you to [this link](https://github.com/benelog/multiline/wiki/Non-Maven-Java-project-with-Eclipse). If you are using eclipse, then a minute of setup and it is working. – Michael Plautz Sep 18 '14 at 19:22
  • This annotation-processor is not supported anymore by Eclipse Neon – Tobia Nov 06 '16 at 09:56
  • 7
    This is probably the biggest hack I have ever seen. EDIT: Nevermind... see Bob Albrights answer. – Llew Vallis Apr 18 '18 at 03:52
  • 3
    I made an extension of this project an created a new one which local variables are supported, [take a look at the project](https://github.com/mageddo/mageddo-projects/tree/master/raw-string-literals) – deFreitas Feb 26 '19 at 04:10
  • we can even use html compressor to make things compact . Really an elegant hack... – KnIfER Oct 29 '19 at 17:04
66

Another option may be to store long strings in an external file and read the file into a string.

Josh Curren
  • 10,171
  • 17
  • 62
  • 73
  • 15
    Exactly. Large amounts of text don't belong in Java source; use a resource file of an appropriate format instead, loaded via a call to Class.getResource(String). – erickson May 18 '09 at 16:51
  • 5
    Right! You can use Locale + ResourceBundle's also to easily load the I18N text, and then the String.format() call will parse the "\n"'s as newlines :) Example: String readyStr = String.parse(resourceBundle.getString("introduction")); – ATorras May 18 '09 at 17:13
  • 69
    You shouldn't have to externalize a String just because it's multi-line. What if I have a regex that I want to break up into multiple lines with comments? It looks ugly in Java. The `@` syntax for C# is much cleaner. – Jeremy Stein Oct 16 '09 at 20:45
  • 9
    Skiphoppy doesn't want to bother with the overhead of dealing with files just to use a paragraph length string constant. I use multiline strings all the time in C++, embedded in my source code, where I want them. – Tim Cooper Nov 06 '09 at 05:35
  • 9
    Wow. I can't believe C++ is actually better than Java on this issue! I love multi-line string constants and they DO belong in source in some cases. – User1 Jan 25 '11 at 22:14
  • 3
    Not to nitpick, but I think C++'s strength over Java is generally linguistic flexibility... Java generally offers a tighter language experience as an aid to junior developers, which is a strength in its own right. – Mark McKenna Oct 02 '12 at 13:17
  • 2
    The longer/more complicated any constant gets the more likely it should be externalized. The type of code you write factors in as well--if you are writing one-use lightly maintained programs it's clearer to embed your constants, for enterprise code I've heard it argued that you should externalize absolutely everything (Admittedly this was a while ago in a less agile world). Since we are talking java, we are leaning towards the enterprise/maintainable end so you really should strongly consider externalizing any multi-line strings--or try a language made for lighter-maintenance code (groovy?). – Bill K Sep 25 '14 at 20:34
  • @JeremyStein Java 13 has multiline text blocks, but comments cannot be included within the block, so your use-case is not supported. – erickson Dec 23 '19 at 19:20
  • 1
    @erickson Java’s regex syntax itself [supports comments](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/regex/Pattern.html#COMMENTS) but of course, that would work with an externalized regex as well. But also `"first part" // comment ↲ + "second part" // comment` with proper indentation would work reasonably, so I don’t understand why people kept fighting for multi-line strings as if that was mission-critical to any project… – Holger Jan 04 '22 at 14:56
  • That's a good point, I didn't think about putting comments in the regex itself. ~13 years on, I still prefer external resources to multiline strings, but... live and let live. – erickson Jan 04 '22 at 18:35
61

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();
}
Bob Albright
  • 2,242
  • 2
  • 25
  • 32
  • 18
    Requires shipping the Java code for the class with the final binary. Hmm. – Thorbjørn Ravn Andersen May 18 '10 at 06:13
  • 29
    i can imagine my co-workers reaction when i try to check something like this in... – Landon Kuhn Aug 21 '12 at 19:25
  • 15
    +1. Some lack of imagination by persons voting down. This is a useful construct for writing small utilities, test cases, and even in controlled prod environments. This is a difference maker between dropping out of java into ruby/python/etc or staying here. – WestCoastProjects May 26 '13 at 18:55
  • 1
    Great solution, but unfortunately will not work for android since the it will be executed on emulator or real device and there is no source code there. – evgeny.myasishchev Jul 08 '15 at 11:56
  • Maybe its a Java 8 prob, or something else, but the classLoader in the example doesn't exists. I tried using MyClass.class.getResourceAsStream(...), but it always returns null. Would have been a great quick solution for testing! – Nick May 05 '16 at 20:54
  • 1
    dang - that's the coolest hack I have seen in years... simply brilliant... not because it's a good idea... but it's radical – Jim May 16 '18 at 12:52
  • In some workspaces you will be cruzified for this kind of code. – kiltek Jun 13 '18 at 13:47
  • The declarations `StringBuilder sb = new StringBuilder();` and `String line = null;` in the `S()` method are entirely obsolete. Also, it would be more efficient, when the `readLine()` loop stops once it encounters the first line containing `*/` – Holger Jan 04 '22 at 14:23
61

String.join

Java 8 added a new static method to java.lang.String which offers a slightly better alternative:

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!"
);
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
icza
  • 389,944
  • 63
  • 907
  • 827
  • 5
    Neat and clean solution! No dependency on IDE and preprocessor! No manual `"\n"` is needed, and is aware of portability! – Siu Ching Pong -Asuka Kenji- Dec 01 '17 at 03:24
  • 1
    I understand that my comment is useless, but it is so retarted to seek hacks for such a basic thing as a multiline string literal. Why the heck cannot java still add this into the spec? – dmitry Oct 09 '18 at 16:03
  • 2
    @dmitry it nowadays has. However, a great question is whether the use of `System.getProperty("line.separator")` is improving the portability or downgrading it. The Java language designers decided to always produce the same string regardless of where the code will run, in other words, to consistently use `\n` only. To achieve the same in older versions, such hacks like `String.join(…)` where never necessary, `"First line.\n" + "Second line.\n" + "The rest.\n" + "And the last!\n"` did the job and could be generated by the IDE automatically when pasting text into the string… – Holger Jan 04 '22 at 14:36
  • @Holger Good that it finally happened (however where I write java I'm still stuck with an older version). Regarding line separator I can imagine that it can matter in some applications but in general I used multiline literals for many things in Scala, Python or wherever they were available and never even gave it a second thought because there never were any issues with this. :) – dmitry Jan 04 '22 at 16:17
45

Java 13 and beyond

Multiline Strings are now supported in Java via Text Blocks. In Java 13 and 14, this feature requires you to set the ––enable–preview option when building and running your project. In Java 15 and later, this option is no longer required as Text Blocks have become a standard feature. 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:

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:

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

IntelliJ IDEA provides support for transforming legacy String concatenation blocks to the new multiline String format:

IntelliJ IDEA Text Blocks support

JSON, HTML, XML

The multiline String is especially useful when writing JSON, HTML, or XML.

Consider this example using String concatenation to build a JSON string literal:

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.

With Java Text Blocks, the JSON object can be written like this:

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.

Flow
  • 23,572
  • 15
  • 99
  • 156
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
19

If you define your strings in a properties file it'll look much worse. IIRC, it'll look like:

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. The text files can be either read at runtime or compiled into Java source. 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"
);
Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
18

Pluses are converted to StringBuilder.append, except when both strings are constants so the compiler can combine them at compile time. 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.

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.

Jay
  • 26,876
  • 10
  • 61
  • 112
  • 4
    to be technical, in your first example it generates something more like: String c = new StringBuilder().append(a).append(b).toString(); The difference being that the temporary string builder is out of scope and eligible for garbage collection immediately after the String c=... line, whereas the "temp" string builder would stay around a little longer. – Kip Jun 04 '09 at 16:24
  • True. My point, of course, is to distinguish when a function gets called at run-time versus when the work can be done at compile time. But you are correct. – Jay Jun 08 '09 at 17:05
17

In the IntelliJ IDE you just need to type:

""

Then position your cursor inside the quotation marks and paste your string. The IDE will expand it into multiple concatenated lines.

nurettin
  • 11,090
  • 5
  • 65
  • 85
11
String newline = System.getProperty ("line.separator");
string1 + newline + string2 + newline + string3

But, the best alternative is to use String.format

String multilineString = String.format("%s\n%s\n%s\n",line1,line2,line3);
bluish
  • 26,356
  • 27
  • 122
  • 180
Tom
  • 43,810
  • 29
  • 138
  • 169
  • My opinion is that it removes the plus signs and quotes, making it more readable, specially when there are more than just 3 lines. Not as good as String.format though. – Tom May 18 '09 at 16:43
  • 2
    Stringbuilder example is at least as unreadable. Also, don't forget that "\n" isn't always a newline, but it's fine for linux and unix machines. – Stefan Thyberg May 18 '09 at 16:45
  • Plus, just wanted to mention the existance of StringBuilder. – Tom May 18 '09 at 16:46
  • 4
    Replacing one plus sign with a six-character method name and parentheses doesn't look more readable to me, although apparently you're not the only one who thinks that way. It doesn't remove the quotes, though. They are still there. – skiphoppy May 18 '09 at 16:50
11

Sadly, Java does not have multi-line string literals. 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.

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

Suppose you're in a class called 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. 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();
}
Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
  • Not true anymore about _java doesn't have a standard read all text method..._ — since Java 7 you can use [Files.readAllLines(Path)](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#readAllLines-java.nio.file.Path-) – ccpizza May 24 '19 at 20:57
9

You may use scala-code, which is compatible to java, and allows multiline-Strings enclosed with """:

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:

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:

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

so that you may cut-and-paste it easily into your source.

GKFX
  • 1,386
  • 1
  • 11
  • 30
user unknown
  • 35,537
  • 11
  • 75
  • 121
9

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. I built the following Python script using some of the tricks mentioned above:

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:

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!

scorpiodawg
  • 5,612
  • 3
  • 42
  • 62
7
    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");
Mike
  • 20,010
  • 25
  • 97
  • 140
7

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. 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

Hope that helps!

Rodney P. Barbati
  • 1,883
  • 24
  • 18
7

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.

Thomas Carroll
  • 161
  • 1
  • 13
user54579
  • 4,588
  • 4
  • 23
  • 19
  • 5
    Why do I prefer StringBuilder to the plus notation? – skiphoppy May 18 '09 at 16:44
  • 10
    Efficiency, or rather an often-misguided attempt at it. – Michael Myers May 18 '09 at 16:55
  • 2
    The attempt at efficiency is based, I think, on the fact that the Java compiler implements the string concatenation operator using StringBuilder (StringBuffer in pre-1.5 compilers). There is an old, but well-known article stating that there are performance benefits in certain situations to using StringBuffer (or StringBuilder, now). Here's the link: http://java.sun.com/developer/JDCTechTips/2002/tt0305.html – Paul Morie May 18 '09 at 17:32
  • 6
    Only when the compiler can't do it. For literals and constants, if you use a plus sign, the concatenation is done at compile-time. Using a StringBuilder forces it to happen at runtime, so it's not only more work, it's slower. – johncip May 09 '11 at 07:30
7

See Java Stringfier. Turns your text into a StringBuilder java block escaping if needed.

Leo
  • 1,102
  • 2
  • 11
  • 18
  • 1
    Yes, because I can spend my life copy and pasting into that site. I could also just store them in a file and load that but that is not an ideal solution either. – mjs Jul 26 '17 at 19:36
6

Java 13 preview:

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.

Example:

 String s1 = """
 text
 text
 text
 """;
Lukasz Szozda
  • 162,964
  • 23
  • 234
  • 275
5

An alternative I haven't seen as answer yet is the 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();

Also the fact that java.io.BufferedWriter has a newLine() method is unmentioned.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
5

Use 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:

 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:

<?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.

Eray Balkanli
  • 7,752
  • 11
  • 48
  • 82
jpfreire
  • 1,268
  • 16
  • 23
  • Yes, this is what I use as well, great solution! Move out the SQL or XML into an external XML property file. It does not mess the code up. :) – Laszlo Lugosi Mar 05 '16 at 17:29
  • This does not answer the question. heredoc's are by definition *within the file*. The point is to keep it in one place. – WestCoastProjects Sep 12 '16 at 14:54
5

With JDK/12 early access build # 12, one can now use multiline strings in Java as follows :

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

Morteza Adi
  • 2,413
  • 2
  • 22
  • 37
Naman
  • 27,789
  • 26
  • 218
  • 353
5

A quite efficient and platform independent solution would be using the system property for line separators and the StringBuilder class to build strings:

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();
Gian Marco
  • 22,140
  • 8
  • 55
  • 44
Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
4

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"));
Dan Lo Bianco
  • 31
  • 1
  • 1
4

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

    }
Bruno Lee
  • 1,867
  • 16
  • 17
4

Java15 now supports triple-quoted strings a la Python.

ncmathsadist
  • 4,684
  • 3
  • 29
  • 45
4

Saw all the answers and I think no one referred than in newer version of java you can do this:

String s = """
    This
    is 
    a
    multiline
    string
    """;
System.out.println(s);

This is what it prints:

This
is
a
multiline
string
Yellow
  • 68
  • 6
3

I suggest using a utility as suggested by ThomasP, and then link that into your build process. 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
  2. On each build, run the utility against the resource file to create a revised java source
  3. The Java source contains a header like class TextBlock {... followed by a static string which is auto-generated from the resource file
  4. Build the generated java file with the rest of your code
Yoon5oo
  • 496
  • 5
  • 11
horace
  • 1,263
  • 1
  • 13
  • 12
3

I know this is an old question, however for intersted developers Multi line literals gonna be in #Java12

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

Morteza Adi
  • 2,413
  • 2
  • 22
  • 37
3

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.

Kip
  • 107,154
  • 87
  • 232
  • 265
  • The value in a properties file can span multiple lines: Just end all lines but the last with a backslash. This does leave the problem of what you use as the line separator, as this is platform-specific. I suppose you could use a simple \n and then in your code, after reading the property, do a search-and-replace of \n to line.separator. That seems a little kludgey, but I guess you could write a function that retrieves a property and does this manipulation at the same time. Well, all that assumes that you'd be writing these strings to a file, which is a big assumption. – Jay May 19 '09 at 00:43
2

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, e.g.:

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, e.g.:

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.

2

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!

The only time StringBuilder is more efficient is when multiple statements are used to construct the 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);

Note: Only one StringBuilder is created.

  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.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
2

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.

It would require writing proper plugins for preprocessing files before compilation phase (for ant/maven build) and a plugin to IDE.

From an ideological point of view, it differs nothing from f.g. "generics", that is also a kind of pre-processed syntactic sugar over casting.

It's, however, a lot of work, so I would at your place just use .properties files.

Yoon5oo
  • 496
  • 5
  • 11
Danubian Sailor
  • 1
  • 38
  • 145
  • 223
1

I sometimes use a parallel groovy class just to act as a bag of strings

The java class here

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

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. Just maintain strong-typing practices and it can be pulled off.

Fakeer
  • 985
  • 1
  • 13
  • 29
1

One small trick. Using this I inject javascritp in a dynamically created HTML page

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

}
  • 6
    A poor choice. Use plus signs. Other, higher-rated answers explain why and how. – Ian May 21 '11 at 03:59
1

Using this library

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

Peter Szanto
  • 7,568
  • 2
  • 51
  • 53
1

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. Actually the feature is in preview mode in other releases (at least 13 has it). 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).

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 :).

Chris T
  • 374
  • 2
  • 3
0

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. 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. But if not, that would be a good thing to add.

  • Or, you can use SciTE just to edit your string in wrap-mode, double-quote it, then copy and paste it to Eclipse. –  Aug 26 '09 at 20:38
  • As others have suggested it is better to keep your long strings in external files, so you can modify them without having to recompile, you can pick different resource-directory for different audiences etc. The downside is that this r4equires a bit of overhead, knowing where to read the files from etc. I wish there was a simple but complete code-example on how best to do this –  Aug 26 '09 at 20:41
0

I got a bit annoyed with reading that multiline syntax is indeed been planned for jdk7 (after about how many decades of java existence?). 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.

/*
  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)

0

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.

A simple sample of the code that uses StringTemplate is below. The actual template ("Hello, < name >") could be loaded from an external plain text file. 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());
    }
}

P.S. It's always a good idea to remove large chunks of text from source code for readability and localization purposes.

Ruslan Ulanov
  • 947
  • 1
  • 10
  • 12
0

I see at least one case where it should be avoided to use external files for long strings: if these long string are expected values in a unit-test file, because I think the tests should always be written in a way that they don't rely on any external resource.

Pang
  • 9,564
  • 146
  • 81
  • 122
Deltaplan
  • 9
  • 1
0

The only way I know of is to concatenate multiple lines with plus signs

Josh Curren
  • 10,171
  • 17
  • 62
  • 73