C# # line break functionality equivalent in Java [duplicate] - java

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.

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.

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

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.

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
that you have to activate the corresponding (provided) annotation
processor.
that String variable can not be defined as local variable Check Raw String Literals project where you can define variables as local variables
that String cannot contains other variables as in Visual Basic .Net
with XML literal (<%= variable %>) :-)
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.

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

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

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

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

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.

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.

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

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

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!

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.

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!

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

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.

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

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

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

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.

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

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.

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

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

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.

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

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:
Build a 'textfile to java code' utility & check into version control
On each build, run the utility against the resource file to create a revised java source
The Java source contains a header like
class TextBlock {... followed by a static string which is auto-generated from the resource file
Build the generated java file with the rest of your code

Java15 now supports triple-quoted strings a la Python.

Related

Is there an equivalent of the C# dollar ($) operator in Java? [duplicate]

This question already has answers here:
How to format strings in Java
(10 answers)
Closed 5 years ago.
String building in Java confounds me. I abhore doing things like:
url += "u1=" + u1 + ";u2=" + u2 + ";u3=" + u3 + ";u4=" + u4 + ";";
url += "x=" + u1 + ";y=" + u2 + ";z=" + u3 + ";da1=" + u4 + ";";
url += "qty=1;cost=" + orderTotal + ";ord=" + orderId + "?";
Or, using StringBuilder, something like this:
url.append("u1=");
url.append(u1);
url.append(";u2=");
url.append(u2);
url.append(";u3=");
url.append(u3);
url.append(";u4=");
url.append(u4);
url.append(";");
url.append("x=");
url.append(u1);
url.append(";y=");
url.append(u2);
url.append(";z=");
url.append(u3);
url.append(";da1=");
url.append(u4);
url.append(";");
url.append("qty=1;");
url.append("cost=");
url.append(orderTotal);
url.append(";ord=");
url.append(orderId);
url.append("?");
SURELY I'm missing something. There has GOT to be a better way. Something like:
Instead of:
urlString += "u1=" + u1 + ";u2=" + u2 + ";u3=" + u3 + ";u4=" + u4 + ";";
do:
urlString += Interpolator("u1=%s;u2=%s;u3=%s;u4=%s;", u1, u2, u3, u4);
or:
urlStringBuilder.append(Interpolator("u1=%s;u2=%s;u3=%s;u4=%s;", u1, u2, u3, u4));
If you're using Java 5 or higher, you can use String.format:
urlString += String.format("u1=%s;u2=%s;u3=%s;u4=%s;", u1, u2, u3, u4);
See Formatter for details.
Note that there is no variable interpolation in Java.
Variable interpolation is variable substitution with its value inside a string.
An example in Ruby:
#!/usr/bin/ruby
age = 34
name = "William"
puts "#{name} is #{age} years old"
The Ruby interpreter automatically replaces variables with its values inside a string.
The fact, that we are going to do interpolation is hinted by sigil characters. In Ruby,
it is #{}. In Perl, it could be $, % or #. Java would only print such characters,
it would not expand them.
Variable interpolation is not supported in Java. Instead of this, we
have string formatting.
package com.zetcode;
public class StringFormatting
{
public static void main(String[] args)
{
int age = 34;
String name = "William";
String output = String.format("%s is %d years old.", name, age);
System.out.println(output);
}
}
In Java, we build a new string using the String.format() method. The outcome is the same, but the methods are different.
See http://en.wikipedia.org/wiki/Variable_interpolation
Edit As of 2019, JEP 326 (Raw String Literals) was withdrawn and superseded by multiple JEPs eventually leading to JEP 378: Text Blocks delivered in Java 15.
A text block is a multi-line string literal that avoids the need for most escape sequences, automatically formats the string in a predictable way, and gives the developer control over the format when desired.
However, still no string interpolation:
Non-Goals: …
Text blocks do not directly support string interpolation. Interpolation may be considered in a future JEP. In the meantime, the new instance method String::formatted aids in situations where interpolation might be desired.
Just to add that there is also java.text.MessageFormat with the benefit of having numeric argument indexes.
Appending the 1st example from the documentation
int planet = 7;
String event = "a disturbance in the Force";
String result = MessageFormat.format(
"At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
planet, new Date(), event);
Result:
At 12:30 PM on Jul 3, 2053, there was a disturbance in the Force on planet 7.
String.format() to the rescue!!
You can use Kotlin, the Super (cede of) Java for JVM, it has a nice way of interpolating strings like those of ES5, Ruby and Python.
class Client(val firstName: String, val lastName: String) {
val fullName = "$firstName $lastName"
}

Cleaning a file name in Java

I want to write a script that will clean my .mp3 files.
I was able to write a few line that change the name but I want to write an automatic script that will erase all the undesired characters $%_!?7 and etc. while changing the name in the next format Artist space dash Song.
File file = new File("C://Users//nikita//Desktop//$%#Artis8t_-_35&Son5g.mp3");
String Original = file.toString();
String New = "Code to change 'Original' to 'Artist - Song'";
File file2 = new File("C://Users//nikita//Desktop//" + New + ".mp3");
file.renameTo(file2);
I feel like I should make a list with all possible characters and then run the String through this list and erase all of the listed characters but I am not sure how to do it.
String test = "$%$#Arti56st_-_54^So65ng.mp3";
Edit 1:
When I try using the method remove, it still doesn't change the name.
String test = "$%$#Arti56st_-_54^So65ng.mp3";
System.out.println("Original: " + test);
test.replace( "[0-9]%#&\\$", "");
System.out.println("New: " + test);
The code above returns the following output
Original: $%$#Arti56st_-_54^So65ng.mp3
New: $%$#Arti56st_-_54^So65ng.mp3
I'd suggest something like this:
public static String santizeFilename(String original){
Pattern p = Pattern.compile("(.*)-(.*)\\.mp3");
Matcher m = p.matcher(original);
if (m.matches()){
String artist = m.group(1).replaceAll("[^a-zA-Z ]", "");
String song = m.group(2).replaceAll("[^a-zA-Z ]", "");
return String.format("%s - %s", artist, song);
}
else {
throw new IllegalArgumentException("Failed to match filename : "+original);
}
}
(Edit - changed whitelist regex to exclude digits and underscores)
Two points in particular - when sanitizing strings, it's a good idea to whitelist permitted characters, rather than blacklisting the ones you want to exclude, so you won't be surprised by edge cases later. (You may want a less restrictive whitelist than I've used here, but it's easy to vary)
It's also a good idea to handle the case that the filename doesn't match the expected pattern. If your code comes across something other than an MP3, how would you like it to respond? Here I've through an exception, so the calling code can catch and handle that appropriately.
String new = original.replace( "[0-9]%#&\\$", "")
this should replace almost all the characters you don't want
or you can come up with your own regex
https://docs.oracle.com/javase/tutorial/essential/regex/

More efficient way to make a string in a string of just words

I am making an application where I will be fetching tweets and storing them in a database. I will have a column for the complete text of the tweet and another where only the words of the tweet will remain (I need the words to calculate which words were most used later).
How I currently do it is by using 6 different .replaceAll() functions which some of them might be triggered twice. For example I will have a for loop to remove every "hashtag" using replaceAll().
The problem is that I will be editing as many as thousands of tweets that I fetch every few minutes and I think that the way I am doing it will not be too efficient.
What my requirements are in this order (also written in comments down bellow):
Delete all usernames mentioned
Delete all RT (retweets flags)
Delete all hashtags mentioned
Replace all break lines with spaces
Replace all double spaces with single spaces
Delete all special characters except spaces
Here is a Short and Compilable Example:
public class StringTest {
public static void main(String args[]) {
String text = "RT #AshStewart09: Vote for Lady Gaga for \"Best Fans\""
+ " at iHeart Awards\n"
+ "\n"
+ "RT!!\n"
+ "\n"
+ "My vote for #FanArmy goes to #LittleMonsters #iHeartAwards"
+ " htt…";
String[] hashtags = {"#FanArmy", "#LittleMonsters", "#iHeartAwards"};
System.out.println("Before: " + text + "\n");
// Delete all usernames mentioned (may run multiple times)
text = text.replaceAll("#AshStewart09", "");
System.out.println("First Phase: " + text + "\n");
// Delete all RT (retweets flags)
text = text.replaceAll("RT", "");
System.out.println("Second Phase: " + text + "\n");
// Delete all hashtags mentioned
for (String hashtag : hashtags) {
text = text.replaceAll(hashtag, "");
}
System.out.println("Third Phase: " + text + "\n");
// Replace all break lines with spaces
text = text.replaceAll("\n", " ");
System.out.println("Fourth Phase: " + text + "\n");
// Replace all double spaces with single spaces
text = text.replaceAll(" +", " ");
System.out.println("Fifth Phase: " + text + "\n");
// Delete all special characters except spaces
text = text.replaceAll("[^a-zA-Z0-9 ]+", "").trim();
System.out.println("Finaly: " + text);
}
}
Relying on replaceAll is probably the biggest performance killer as it compiles the regex again and again. The use of regexes for everything is probably the second most significant problem.
Assuming all usernames start with #, I'd replace
// Delete all usernames mentioned (may run multiple times)
text = text.replaceAll("#AshStewart09", "");
by a loop copying everything until it founds a #, then checking if the following chars match any of the listed usernames and possibly skipping them. For this lookup you could use a trie. A simpler method would be a replaceAll-like loop for the regex #\w+ together with a HashMap lookup.
// Delete all RT (retweets flags)
text = text.replaceAll("RT", "");
Here,
private static final Pattern RT_PATTERN = Pattern.compile("RT");
is a sure win. All the following parts could be handled similarly. Instead of
// Delete all special characters except spaces
text = text.replaceAll("[^a-zA-Z0-9 ]+", "").trim();
you could use Guava's CharMatcher. The method removeFrom does exactly what you did, but collapseFrom or trimAndCollapseFrom might be better.
According to the now closed question, it all boils down to
tweet = tweet.replaceAll("#\\w+|#\\w+|\\bRT\\b", "")
.replaceAll("\n", " ")
.replaceAll("[^\\p{L}\\p{N} ]+", " ")
.replaceAll(" +", " ")
.trim();
The second line seems to be redundant as the third one does remove \n too. Changing the first line's replacement to " " doesn't change the outcome an allows to aggregate the replacements.
tweet = tweet.replaceAll("#\\w*|#\\w*|\\bRT\\b|[^##\\p{L}\\p{N} ]+", " ")
.replaceAll(" +", " ")
.trim();
I've changed the usernames and hashtags part to eating also lone # or #, so that it doesn't need to be consumed by the special chars part. This is necessary for corrent processing of strings like !#AshStewart09.
For maximum performance, you surely need a precompiled pattern. I'd also re-suggest to use Guava's CharMatcher for the second part. Guava is huge (2 MB I guess), but you surely find more useful things there. So in the end you can get
private static final Pattern PATTERN =
Pattern.compile("#\\w*|#\\w*|\\bRT\\b|[^##\\p{L}\\p{N} ]+");
private static final CharMatcher CHAR_MATCHER = CharMacher.is(" ");
tweet = PATTERN.matcher(tweet).replaceAll(" ");
tweet = CHAR_MATCHER.trimAndCollapseFrom(tweet, " ");
You can inline all of the things that are being replaced with nothing into one call to replace all and everything that is replaced with a space into one call like so (also using a regex to find the hashtags and usernames as this seems easier):
text = text.replaceAll("#\w+|#\w+|RT", "");
text = text.replaceAll("\n| +", " ");
text = text.replaceAll("[^a-zA-Z0-9 ]+", "").trim();

\n won't work, not going to a new line

I'm creating a small program that saves a int value into a text file, saves it, and loads it when you start the program again. Now, I need 3 more booleans to be stored in the text file, I am writing things in the file with
public Formatter x;
x.format("%s", "" + m.getPoints() + "\n");
Whenever I want to go to a new line in my text file, with \n, it wont go to a new line, it will just write it directly behind the int value. I tried doing both
x.format("%s", "" + m.getPoints() + "\n");
x.format("%s", "" + m.getStoreItem1Bought() + "\n");
and
x.format("%s%s", "" + m.getPoints() + "\n", "" + m.getBought() + "\n");
but, both will just write the boolean directly behind the int value, without starting a new line. Any help on this?
I am using Windows 7 Ultimate 64 bits, and my text editor is Eclipse, I am running all of the code with Eclipse too.
More specifically, I would recommend using:
x.format("%d%n%s%n", m.getPoints(), m.getStoreItem1Bought());
Use this instead:
public static String newline = System.getProperty("line.separator");
Both of this options work. Your problem is in how you format the output:
System.out.format("%s" + newline + "%s" + newline, "test1", "test2");
System.out.format("%s%n%s", "test1", "test2");
Output:
test1
test2
test1
test2
Try using %n instead of \n when using format. For details on this, please see the Formatter API and search this page for "line separator" and you'll see.
No problem here:
System.out.format ("first: %s%s", "" + x + "\n", "" + y + "\n");
While I would prefere, to integrate the \n into the format String, not the values:
System.out.format ("second: %s\n%s\n", x, y);
Using Formatter.format works the same.
Well your syntax is surely quite.. interesting. Why use the formatting method if you're just piece the string together anyways? Also since you nowhere say what stream you're using we have to guess a bit, but anyways.
Anyways I'm betting that 1. you're using windows and 2. that the editor (I bet on notepad) you're using only reacts to \r\n since that's the correct newline for Windows. To fix this DON'T hardcode \r\n in your code but instead use %n and use the printf function correctly (ie don't piece the string together!).
Otherwise if you really have to piece the string together:
String newline = System.getProperty("line.separator");
x.format("%s", "" + m.getPoints() + newline);
will work.

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:
$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.
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.
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";
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.
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
that you have to activate the corresponding (provided) annotation
processor.
that String variable can not be defined as local variable Check Raw String Literals project where you can define variables as local variables
that String cannot contains other variables as in Visual Basic .Net
with XML literal (<%= variable %>) :-)
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.
Another option may be to store long strings in an external file and read the file into a string.
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:
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!"
);
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:
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.
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"
);
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.
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.
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();
}
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);
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!
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.
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!
See Java Stringfier. Turns your text into a StringBuilder java block escaping if needed.
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.
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");
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
""";
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
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.
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();
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.
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"));
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);
}
}
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.
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
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:
Build a 'textfile to java code' utility & check into version control
On each build, run the utility against the resource file to create a revised java source
The Java source contains a header like
class TextBlock {... followed by a static string which is auto-generated from the resource file
Build the generated java file with the rest of your code
Java15 now supports triple-quoted strings a la Python.

Categories

Resources