Mehrzeiliger Java-String

516

Ich komme aus Perl und vermisse sicher die "Here-Document" -Methode zum Erstellen einer mehrzeiligen Zeichenfolge im Quellcode:

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

In Java muss ich umständliche Anführungszeichen und Pluszeichen in jeder Zeile haben, wenn ich meine mehrzeilige Zeichenfolge von Grund auf verkette.

Was sind bessere Alternativen? Meine Zeichenfolge in einer Eigenschaftendatei definieren?

Bearbeiten : Zwei Antworten besagen, dass StringBuilder.append () der Plus-Notation vorzuziehen ist. Könnte jemand erläutern, warum er so denkt? Es sieht für mich überhaupt nicht besser aus. Ich suche nach einem Weg, um die Tatsache zu umgehen, dass mehrzeilige Zeichenfolgen kein erstklassiges Sprachkonstrukt sind, was bedeutet, dass ich ein erstklassiges Sprachkonstrukt (Zeichenfolgenverkettung mit Plus) definitiv nicht durch Methodenaufrufe ersetzen möchte.

Bearbeiten : Um meine Frage weiter zu klären, mache ich mir überhaupt keine Sorgen um die Leistung. Ich mache mir Sorgen um Wartbarkeit und Designprobleme.

Skiphoppy
quelle
12
StringBuilder.append () ist beim wiederholten Hinzufügen zu einer Zeichenfolge dem Plus vorzuziehen, da Sie jedes Mal string1 + string2ein neues Zeichenfolgenobjekt zuweisen und die Zeichen aus beiden Eingabezeichenfolgen kopieren. Wenn Sie n Strings addieren, führen Sie n-1 Zuweisungen und ungefähr (n ^ 2) / 2 Zeichenkopien durch. StringBuilder hingegen kopiert und ordnet weniger häufig neu zu (obwohl es immer noch beides tut, wenn Sie die Größe seines internen Puffers überschreiten). Theoretisch gibt es Fälle, in denen der Compiler + konvertieren könnte, um StringBuilder zu verwenden, aber in der Praxis, wer weiß.
Laurence Gonsalves
5
Jedes Mal, wenn ich in den Debugger springe, wird + unter Java 1.5 in einen StringBuilder.append () -Aufruf konvertiert. Ich habe von Kollegen verwirrt erfahren, dass StringBuilder einen Fehler hat, da sie in Code debuggen, der ihn anscheinend nicht aufruft, und dort landen.
Skiphoppy
4
Siehe auch: stackoverflow.com/questions/782810/…
Michael Myers
61
Beachten Sie, dass ein String-Literal aus "abc \ n" + "def \ n" usw. keinen StringBuilder verwendet: Der Compiler klebt sie zusammen und fügt sie wie bei anderen Typen von als einzelnes Literal in die .class-Datei ein ständiges Falten.
Araqnid
6
Die meisten IDEs unterstützen die Eingabe mehrzeiliger Zeichenfolgen. dh. Sie geben einfach das gewünschte Zeichen ein oder fügen es in eine Zeichenfolge "" ein. Anschließend werden die Zeichen \ n und "+" nach Bedarf hinzugefügt. zB kann ich 40 Textzeilen in einen String einfügen und die IDE sortiert ihn für Sie.
Peter Lawrey

Antworten:

118

Stephen Colebourne hat einen Vorschlag zum Hinzufügen mehrzeiliger Zeichenfolgen in Java 7 erstellt.

Außerdem unterstützt Groovy bereits mehrzeilige Zeichenfolgen .

Paul Morie
quelle
14
Der Project Coin-Prozess für Verbesserungen an Java umfasste mehrzeilige Zeichenfolgen mail.openjdk.java.net/pipermail/coin-dev/2009-February/… . Es wurde von Oracle blogs.sun.com/darcy/entry/project_coin_final_five abgelehnt .
JodaStephen
8
eine Änderung im Jahr 2012?
Ilia G
13
Leider scheint dies nicht in die Spezifikation gekommen zu sein.
Namuol
3
Der Link zu blogs.sun.com ist defekt, aber ich denke, der Inhalt befindet sich jetzt unter blogs.oracle.com/darcy/entry/project_coin_final_five .
Donal Fellows
8
Ab Januar 2018 erwägt die Community anscheinend mehrzeilige Zeichenfolgen. openjdk.java.net/jeps/326
Shane Gannon
485

Es hört sich so an, als ob Sie ein mehrzeiliges Literal erstellen möchten, das in Java nicht vorhanden ist.

Ihre beste Alternative werden Saiten sein, die nur +zusammen passen. Einige andere Optionen, die bereits erwähnt wurden (StringBuilder, String.format, String.join), sind nur vorzuziehen, wenn Sie mit einem Array von Zeichenfolgen begonnen haben.

Bedenken Sie:

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

Wenn Sie das Newline für Ihr spezielles System wollen, müssen Sie entweder die Verwendung System.lineSeparator()oder Sie verwenden können , %nin String.format.

Eine andere Möglichkeit besteht darin, die Ressource in eine Textdatei einzufügen und nur den Inhalt dieser Datei zu lesen. Dies ist für sehr große Zeichenfolgen vorzuziehen, um ein unnötiges Aufblähen Ihrer Klassendateien zu vermeiden.

Kip
quelle
246
Darüber hinaus wird die erste Version vom Compiler automatisch verkettet, da alle Zeichenfolgen zur Kompilierungszeit bekannt sind. Auch wenn die Zeichenfolgen zur Kompilierungszeit nicht bekannt sind, sind sie nicht langsamer als StringBuilder oder String.format (). Der einzige Grund, eine Verkettung mit + zu vermeiden, besteht darin, dass Sie dies in einer Schleife tun.
Michael Myers
23
Das Problem mit der String.formatVersion ist, dass Sie das Format mit der Anzahl der Zeilen synchron halten müssen.
Bart van Heukelom
4
String.format ist nicht effizient im Vergleich zu anderen zwei Beispielen
cmcginty
10
Diese Antwort ist eine sehr unangemessene Lösung für die vorliegende Frage. Wir haben SAS-Makros mit 2000 Zeilen oder Bündel von SQL-Abfragen mit 200 Zeilen, die wir kopieren und einfügen möchten. Es ist lächerlich zu behaupten, dass wir + "" concat verwenden, um diesen mehrzeiligen Text in StringBuffer-Anhänge umzuwandeln.
Seliger Geek
21
@BlessedGeek: Die Frage war, welche Optionen in der Java-Sprache verfügbar waren. Es wurde nichts über die Art der Daten erwähnt, die in die Zeichenfolge eingehen. Wenn es eine bessere Lösung gibt, können Sie sie als Antwort veröffentlichen. Es klingt so, als wäre die Lösung von Josh Curren besser für Ihre Situation. Wenn Sie nur verärgert sind, dass die Sprache keine mehrzeiligen Literale unterstützt, ist dies der falsche Ort, um sich darüber zu beschweren.
Kip
188

Wenn Sie in Eclipse die Option "Escape-Text beim Einfügen in ein Zeichenfolgenliteral" aktivieren (unter Einstellungen> Java> Editor> Eingabe) und eine mehrzeilige Zeichenfolge in Anführungszeichen einfügen, wird automatisch "und \n" +für alle Ihre Zeilen hinzugefügt .

String str = "paste your text here";
Monir
quelle
15
intelij macht dies auch standardmäßig, wenn Sie in "" s
Bob B
Verlassen Sie im Allgemeinen das \rs, das Eclipse unter Windows einfügt?
Noumenon
99

Dies ist ein alter Thread, aber eine neue, recht elegante Lösung (mit nur 4 oder 3 kleinen Nachteilen) besteht darin, eine benutzerdefinierte Anmerkung zu verwenden.

Überprüfen Sie: http://www.adrianwalker.org/2011/12/java-multiline-string.html

Ein von dieser Arbeit inspiriertes Projekt wird auf GitHub gehostet:

https://github.com/benelog/multiline

Beispiel für 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);
  }
}

Die Nachteile sind

  1. dass Sie den entsprechenden (mitgelieferten) Anmerkungsprozessor aktivieren müssen.
  2. Diese String-Variable kann nicht als lokale Variable definiert werden. Überprüfen Sie das Raw Raw String Literals-Projekt, in dem Sie Variablen als lokale Variablen definieren können
  3. Dieser String kann keine anderen Variablen wie in Visual Basic .Net mit XML-Literal ( <%= variable %>) enthalten :-)
  4. Dieses String-Literal wird durch einen JavaDoc-Kommentar (/ **) begrenzt.

Und Sie müssen wahrscheinlich Eclipse / Intellij-Idea so konfigurieren, dass Ihre Javadoc-Kommentare nicht automatisch neu formatiert werden.

Man mag dies seltsam finden (Javadoc-Kommentare sind nicht dazu gedacht, etwas anderes als Kommentare einzubetten), aber da dieser Mangel an mehrzeiligen Zeichenfolgen in Java am Ende wirklich ärgerlich ist, finde ich dies die am wenigsten schlimmste Lösung.

SRG
quelle
Erfordert dies, dass die Klasse, die die mehrzeilige Zeichenfolge verwendet, endgültig ist? Ist beim Entwickeln und Ausführen von Code aus Eclipse ein Setup erforderlich? In der Referenz-URL werden die Setup-Anforderungen für Maven für die Verarbeitung von Anmerkungen erwähnt. Ich kann nicht herausfinden, was in Eclipse möglicherweise benötigt wird.
David
Die Anmerkung ist lebenswert - aber es scheint, dass es auch eine harte Abhängigkeit von Maven gab? Dieser Teil nimmt einen großen Teil des Wertes von Heredocs weg, die die Verwaltung kleiner Textteile vereinfachen sollen.
Javadba
3
Sie können dies vollständig in Eclipse tun. Der Link, den @SRG oben gepostet hat, verweist auf diesen Link . Wenn Sie Eclipse verwenden, dann eine Minute Setup und es funktioniert.
Michael Plautz
4
Dies ist wahrscheinlich der größte Hack, den ich je gesehen habe. EDIT: Nevermind ... siehe Bob Albrights Antwort.
Llew Vallis
1
Ich habe eine Erweiterung dieses Projekts erstellt und eine neue erstellt, bei der lokale Variablen unterstützt werden. Schauen Sie sich das Projekt an
deFreitas
62

Eine andere Möglichkeit kann darin bestehen, lange Zeichenfolgen in einer externen Datei zu speichern und die Datei in eine Zeichenfolge einzulesen.

Josh Curren
quelle
13
Genau. Große Textmengen gehören nicht in die Java-Quelle. Verwenden Sie stattdessen eine Ressourcendatei in einem geeigneten Format, die über einen Aufruf von Class.getResource (String) geladen wird.
erickson
5
Recht! Sie können Locale + ResourceBundle auch verwenden, um den I18N-Text einfach zu laden. Anschließend analysiert der Aufruf von String.format () die "\ n" als Zeilenumbrüche :) Beispiel: String readyStr = String.parse (resourceBundle.getString (") Einführung"));
ATorras
62
Sie sollten einen String nicht externalisieren müssen, nur weil er mehrzeilig ist. Was ist, wenn ich einen regulären Ausdruck habe, den ich mit Kommentaren in mehrere Zeilen aufteilen möchte? In Java sieht es hässlich aus. Die @Syntax für C # ist viel sauberer.
Jeremy Stein
8
Skiphoppy möchte sich nicht um den Aufwand beim Umgang mit Dateien kümmern, nur um eine Zeichenfolgenkonstante mit Absatzlänge zu verwenden. Ich verwende in C ++ ständig mehrzeilige Zeichenfolgen, die in meinen Quellcode eingebettet sind, wo ich sie haben möchte.
Tim Cooper
9
Beeindruckend. Ich kann nicht glauben, dass C ++ in dieser Frage tatsächlich besser ist als Java! Ich liebe mehrzeilige String-Konstanten und sie gehören in einigen Fällen zur Quelle.
User1
59

Dies ist etwas, das Sie niemals verwenden sollten , ohne darüber nachzudenken, was es tut. Aber für einmalige Skripte habe ich dies mit großem Erfolg verwendet:

Beispiel:

    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
quelle
15
Erfordert den Versand des Java-Codes für die Klasse mit der endgültigen Binärdatei. Hmm.
Thorbjørn Ravn Andersen
23
Ich kann mir vorstellen, wie meine Mitarbeiter reagieren, wenn ich versuche, so etwas in ...
Landon Kuhn
15
+1. Einige mangelnde Vorstellungskraft von Personen, die abstimmen. Dies ist ein nützliches Konstrukt zum Schreiben kleiner Dienstprogramme, Testfälle und sogar in kontrollierten Produktumgebungen. Dies ist ein Unterschied zwischen dem Ausstieg aus Java in Ruby / Python / etc oder dem Aufenthalt hier.
Javadba
1
Tolle Lösung, funktioniert aber leider nicht für Android, da sie auf einem Emulator oder einem realen Gerät ausgeführt wird und dort kein Quellcode vorhanden ist.
evgeny.myasishchev
Vielleicht ist es ein Java 8-Problem oder etwas anderes, aber der classLoader im Beispiel existiert nicht. Ich habe versucht, MyClass.class.getResourceAsStream (...) zu verwenden, aber es wird immer null zurückgegeben. Wäre eine tolle schnelle Lösung zum Testen gewesen!
Nick
54

String.join

Java 8 hat eine neue statische Methode hinzugefügt, java.lang.Stringdie eine etwas bessere Alternative bietet:

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

Es benutzen:

String s = String.join(
    System.getProperty("line.separator"),
    "First line.",
    "Second line.",
    "The rest.",
    "And the last!"
);
icza
quelle
5
Ordentliche und saubere Lösung! Keine Abhängigkeit von IDE und Präprozessor! Es "\n"wird kein Handbuch benötigt und ist sich der Portabilität bewusst!
Siu Ching Pong -Asuka Kenji-
1
Ich verstehe, dass mein Kommentar nutzlos ist, aber es wird so neu gestartet, um Hacks für eine so grundlegende Sache wie ein mehrzeiliges String-Literal zu suchen. Warum zum Teufel kann Java das nicht noch in die Spezifikation aufnehmen?
dmitry
22

JEP 355: Textblöcke (Vorschau) soll diese Funktionalität abdecken. Derzeit wird JDK 13 als Vorschaufunktion verwendet. Erlauben, etwas zu schreiben wie:

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

Vor diesem JEP in JDK12 zielte JEP 326: Raw String Literals darauf ab, eine ähnliche Funktion zu implementieren, die jedoch endgültig zurückgezogen wurde.

alostale
quelle
2
Sie ließen diese Unterstützung fallen
deFreitas
2
Textblöcke sind jetzt Teil von Java 13.
ZhekaKozlov
19

Wenn Sie Ihre Zeichenfolgen in einer Eigenschaftendatei definieren, sieht es viel schlechter aus. IIRC, es wird aussehen wie:

string:text\u000atext\u000atext\u000a

Im Allgemeinen ist es eine vernünftige Idee, keine großen Zeichenfolgen in die Quelle einzubetten. Möglicherweise möchten Sie sie als Ressourcen laden, möglicherweise in XML oder einem lesbaren Textformat. Die Textdateien können entweder zur Laufzeit gelesen oder in eine Java-Quelle kompiliert werden. Wenn Sie sie am Ende in der Quelle platzieren, empfehle ich, die +an die Vorderseite zu setzen und unnötige neue Zeilen wegzulassen:

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

Wenn Sie neue Zeilen haben, möchten Sie möglicherweise einige Verknüpfungs- oder Formatierungsmethoden:

final String text = join("\r\n"
    ,"text"
    ,"text"
    ,"text"
);
Tom Hawtin - Tackline
quelle
17

Pluspunkte werden in StringBuilder.append konvertiert, außer wenn beide Zeichenfolgen Konstanten sind, damit der Compiler sie zur Kompilierungszeit kombinieren kann. Zumindest ist das in Suns Compiler so, und ich würde die meisten vermuten, wenn nicht alle anderen Compiler dasselbe tun würden.

Damit:

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

generiert normalerweise genau den gleichen Code wie:

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

Auf der anderen Seite:

String c="Hello"+"Goodbye";

ist das gleiche wie:

String c="HelloGoodbye";

Das heißt, es gibt keine Strafe, wenn Sie Ihre String-Literale über mehrere Zeilen mit Pluszeichen für die Lesbarkeit aufteilen.

Jay
quelle
4
Um technisch zu sein, generiert es in Ihrem ersten Beispiel mehr wie folgt: String c = new StringBuilder (). append (a) .append (b) .toString (); Der Unterschied besteht darin, dass der temporäre String-Builder außerhalb des Gültigkeitsbereichs liegt und unmittelbar nach der String c = ... -Zeile für die Speicherbereinigung in Frage kommt, während der "temporäre" String-Builder etwas länger bleiben würde.
Kip
Wahr. Mein Punkt ist natürlich zu unterscheiden, wann eine Funktion zur Laufzeit aufgerufen wird und wann die Arbeit zur Kompilierungszeit ausgeführt werden kann. Aber du hast recht.
Jay
15

In der IntelliJ IDE müssen Sie nur Folgendes eingeben:

""

Positionieren Sie dann den Cursor innerhalb der Anführungszeichen und fügen Sie die Zeichenfolge ein. Die IDE erweitert es in mehrere verkettete Zeilen.

nurettin
quelle
11

Leider verfügt Java nicht über mehrzeilige Zeichenfolgenliterale. Sie müssen entweder Zeichenfolgenliterale verketten (wobei + oder StringBuilder die beiden am häufigsten verwendeten Ansätze sind) oder die Zeichenfolge aus einer separaten Datei einlesen.

Bei großen mehrzeiligen Zeichenfolgenliteralen würde ich gerne eine separate Datei verwenden und diese mit getResourceAsStream()(einer Methode der ClassKlasse) einlesen . Dies erleichtert das Auffinden der Datei, da Sie sich keine Gedanken über das aktuelle Verzeichnis und den Installationsort Ihres Codes machen müssen. Dies erleichtert auch das Verpacken, da Sie die Datei tatsächlich in Ihrer JAR-Datei speichern können.

Angenommen, Sie sind in einer Klasse namens Foo. Mach einfach so etwas:

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

Das einzige andere Ärgernis ist, dass Java nicht über die Standardmethode "Lesen Sie den gesamten Text dieses Readers in einen String" verfügt. Es ist allerdings ziemlich einfach zu schreiben:

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
quelle
Ich mache dasselbe. Sie können commons-io verwenden, um den Inhalt der Datei einfacher zu lesen (mit "FileUtils.readFileToString (File file)").
SRG
Nicht mehr wahr über Java hat keine Standard-Read-All-Text-Methode ... - Seit Java 7 können Sie Files.readAllLines (Path) verwenden
ccpizza
10
String newline = System.getProperty ("line.separator");
string1 + newline + string2 + newline + string3

Die beste Alternative ist jedoch die Verwendung von String.format

String multilineString = String.format("%s\n%s\n%s\n",line1,line2,line3);
Tom
quelle
Meiner Meinung nach werden die Pluszeichen und Anführungszeichen entfernt, wodurch die Lesbarkeit verbessert wird, insbesondere wenn mehr als nur 3 Zeilen vorhanden sind. Nicht so gut wie String.format.
Tom
2
Das Stringbuilder-Beispiel ist mindestens genauso unlesbar. Vergessen Sie auch nicht, dass "\ n" nicht immer eine neue Zeile ist, aber für Linux- und Unix-Computer in Ordnung.
Stefan Thyberg
Außerdem wollte ich nur die Existenz von StringBuilder erwähnen.
Tom
4
Das Ersetzen eines Pluszeichens durch einen sechsstelligen Methodennamen und Klammern erscheint mir nicht besser lesbar, obwohl Sie anscheinend nicht der einzige sind, der so denkt. Die Anführungszeichen werden jedoch nicht entfernt. Sie sind immer noch da.
Skiphoppy
9

Da Java (noch) nicht native mehrzeilige Zeichenfolgen unterstützt, besteht die einzige Möglichkeit im Moment darin, sie mit einer der oben genannten Techniken zu umgehen. Ich habe das folgende Python-Skript mit einigen der oben genannten Tricks erstellt:

import sys
import string
import os

print 'new String('
for line in sys.stdin:
    one = string.replace(line, '"', '\\"').rstrip(os.linesep)
    print '  + "' + one + ' "'
print ')'

Fügen Sie dies in eine Datei mit dem Namen javastringify.py und Ihre Zeichenfolge in eine Datei mystring.txt ein und führen Sie sie wie folgt aus:

cat mystring.txt | python javastringify.py

Sie können die Ausgabe dann kopieren und in Ihren Editor einfügen.

Ändern Sie dies nach Bedarf, um Sonderfälle zu behandeln, aber dies funktioniert für meine Anforderungen. Hoffe das hilft!

Scorpiodawg
quelle
9

Sie können Scala-Code verwenden, der mit Java kompatibel ist und mehrzeilige Zeichenfolgen zulässt, die mit "" "eingeschlossen sind:

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

(Beachten Sie die Anführungszeichen in der Zeichenfolge) und aus Java:

String s2 = foobar.SWrap.bar ();

Ob das bequemer ist ...?

Ein anderer Ansatz, wenn Sie häufig langen Text verarbeiten, der in Ihren Quellcode eingefügt werden sollte, könnte ein Skript sein, das den Text aus einer externen Datei entnimmt und wie folgt in einen mehrzeiligen Java-String umschließt:

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

damit Sie es einfach ausschneiden und in Ihre Quelle einfügen können.

Benutzer unbekannt
quelle
8

Sie können Ihre Anhänge in einer separaten Methode verketten:

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

In beiden Fällen bevorzugen Sie StringBuilderdie Plus-Notation.

Benutzer54579
quelle
5
Warum ziehe ich StringBuilder der Plus-Notation vor?
Skiphoppy
10
Effizienz oder vielmehr ein oft fehlgeleiteter Versuch.
Michael Myers
2
Der Versuch der Effizienz basiert meiner Meinung nach auf der Tatsache, dass der Java-Compiler den String-Verkettungsoperator mit StringBuilder (StringBuffer in Compilern vor 1.5) implementiert. Es gibt einen alten, aber bekannten Artikel, der besagt, dass die Verwendung von StringBuffer (oder jetzt StringBuilder) in bestimmten Situationen Leistungsvorteile bietet. Hier ist der Link: java.sun.com/developer/JDCTechTips/2002/tt0305.html
Paul Morie
4
Nur wenn der Compiler das nicht kann. Wenn Sie für Literale und Konstanten ein Pluszeichen verwenden, erfolgt die Verkettung zur Kompilierungszeit. Die Verwendung eines StringBuilder erzwingt dies zur Laufzeit, sodass nicht nur mehr Arbeit, sondern auch langsamer erfolgt.
Johncip
7

Das Folgende ist die sauberste Implementierung, die ich bisher gesehen habe. Es verwendet eine Anmerkung, um einen Kommentar in eine Zeichenfolgenvariable umzuwandeln ...

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

Das Endergebnis ist also, dass die Variable HTML die mehrzeilige Zeichenfolge enthält. Keine Anführungszeichen, keine Pluszeichen, keine Kommas, nur reine Zeichenfolge.

Diese Lösung ist unter der folgenden URL verfügbar ... http://www.adrianwalker.org/2011/12/java-multiline-string.html

Ich hoffe, das hilft!

Rodney P. Barbati
quelle
Dieser Annotationsprozessor muss robuster überprüft werden
Tripp Kinetics
Ich mag das. Probieren Sie es aus
javadba
7

Siehe Java Stringfier . Verwandelt Ihren Text in einen StringBuilder-Java-Block, der bei Bedarf ausgeblendet wird.

Leo
quelle
1
Ja, weil ich mein Leben damit verbringen kann, diese Site zu kopieren und einzufügen. Ich könnte sie auch einfach in einer Datei speichern und laden, aber das ist auch keine ideale Lösung.
mmm
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");
Mykhaylo Adamovych
quelle
6

Eine Alternative, die ich noch nicht als Antwort gesehen habe, ist die 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();

Auch die Tatsache, dass java.io.BufferedWriteres eine newLine()Methode gibt, wird nicht erwähnt.

BalusC
quelle
5

Wenn Sie Googles Guave genauso mögen wie ich, kann dies eine ziemlich saubere Darstellung und eine schöne, einfache Möglichkeit bieten, auch Ihre Zeilenumbruchzeichen nicht fest zu codieren:

String out = Joiner.on(newline).join(ImmutableList.of(
    "line1",
    "line2",
    "line3"));
Dan Lo Bianco
quelle
5

Verwenden Sie Properties.loadFromXML(InputStream). Es sind keine externen Bibliotheken erforderlich.

Besser als ein unordentlicher Code (da Wartbarkeit und Design Ihr Anliegen sind), ist es vorzuziehen, keine langen Zeichenfolgen zu verwenden.

Beginnen Sie mit dem Lesen der XML-Eigenschaften:

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


Dann können Sie Ihre mehrzeilige Zeichenfolge auf eine wartbarere Weise verwenden ...

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


MultiLine.xml` befindet sich im selben Ordner 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.: Sie können <![CDATA["... "]]>für XML-ähnliche Zeichenfolgen verwenden.

jpfreire
quelle
Ja, das ist es, was ich auch benutze, tolle Lösung! Verschieben Sie SQL oder XML in eine externe XML-Eigenschaftendatei. Es bringt den Code nicht durcheinander. :)
Laszlo Lugosi
Dies beantwortet die Frage nicht. Heredocs sind per Definition in der Datei . Der Punkt ist, es an einem Ort zu halten.
Javadba
5

Mit JDK / 12 Early Access Build Nr. 12 können jetzt mehrzeilige Zeichenfolgen in Java wie folgt verwendet werden:

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

und dies führt zu folgender Ausgabe:

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

Bearbeiten: Auf Java 13 verschoben

Naman
quelle
1
Hier ist eine Möglichkeit, es mit Maven auszuprobieren
Naman
2
Wie Cybersoft in einem anderen Kommentar sagt, wurden rohe String-Literale (JEP326) aus dem endgültigen JDK12 entfernt, aber ein weiteres JEP wurde erstellt, um "Textblöcke" hinzuzufügen, die als Vorschau in JDK 13
Manuel Romeiro
4

Eine recht effiziente und plattformunabhängige Lösung wäre die Verwendung der Systemeigenschaft für Zeilentrennzeichen und der StringBuilder-Klasse zum Erstellen von Zeichenfolgen:

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();
Andreas_D
quelle
4

Eine gute 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
quelle
4

Dies ist eine sehr häufige Frage, daher habe ich beschlossen, diese Antwort auch in einen Artikel umzuwandeln .

Java 13 und darüber hinaus

Mehrzeilige Zeichenfolgen werden jetzt in Java über Textblöcke unterstützt . In Java 13 und 14 müssen Sie für diese Funktion die Einstellungen vornehmen––enable–preview Option wenn Sie Ihr Projekt erstellen und ausführen. Weitere Informationen finden Sie in dieser Java-Dokumentation .

Vor Java 13 schreiben Sie eine Abfrage folgendermaßen:

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

Dank Java 13-Textblöcken können Sie diese Abfrage wie folgt umschreiben:

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

Viel lesbarer, oder?

IDE-Unterstützung

IntelliJ IDEA bietet Unterstützung für die Umwandlung älterer StringVerkettungsblöcke in das neue mehrzeilige StringFormat:

Unterstützung für IntelliJ IDEA-Textblöcke

JSON, HTML, XML

Die mehrzeilige String ist besonders nützlich, wenn Sie JSON, HTML oder XML schreiben.

Betrachten Sie dieses Beispiel mithilfe der StringVerkettung, um ein JSON-Zeichenfolgenliteral zu erstellen:

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" +
        "       }" +
        "   ]" +
        "}"
    )
);

Sie können den JSON aufgrund der entweichenden Zeichen und der Fülle an doppelten Anführungszeichen und Pluszeichen kaum lesen.

Mit Java-Textblöcken kann das JSON-Objekt folgendermaßen geschrieben werden:

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

Seit ich 2004 C # verwendet habe, wollte ich diese Funktion in Java haben, und jetzt haben wir sie endlich.

Vlad Mihalcea
quelle
3

Meine Zeichenfolge in einer Eigenschaftendatei definieren?

Mehrzeilige Zeichenfolgen sind in Eigenschaftendateien nicht zulässig. Sie können \ n in Eigenschaftendateien verwenden, aber ich denke nicht, dass dies in Ihrem Fall eine gute Lösung ist.

Pennen
quelle
Der Wert in einer Eigenschaftendatei kann mehrere Zeilen umfassen: Beenden Sie einfach alle Zeilen bis auf die letzte mit einem Backslash. Dies führt jedoch zu dem Problem, was Sie als Zeilentrennzeichen verwenden, da dies plattformspezifisch ist. Ich nehme an, Sie könnten ein einfaches \ n verwenden und dann in Ihrem Code nach dem Lesen der Eigenschaft ein Suchen und Ersetzen von \ n für line.separator durchführen. Das scheint ein wenig kludgey, aber ich denke, Sie könnten eine Funktion schreiben, die eine Eigenschaft abruft und diese Manipulation gleichzeitig ausführt. Nun, all das setzt voraus, dass Sie diese Zeichenfolgen in eine Datei schreiben, was eine große Annahme ist.
Jay
3

Ich schlage vor, ein von ThomasP vorgeschlagenes Dienstprogramm zu verwenden und dieses dann mit Ihrem Erstellungsprozess zu verknüpfen. Es ist noch eine externe Datei vorhanden, die den Text enthält, aber die Datei wird zur Laufzeit nicht gelesen. Der Workflow lautet dann:

  1. Erstellen Sie ein Dienstprogramm "Textdatei in Java-Code" und checken Sie in die Versionskontrolle ein
  2. Führen Sie das Dienstprogramm bei jedem Build für die Ressourcendatei aus, um eine überarbeitete Java-Quelle zu erstellen
  3. Die Java-Quelle enthält einen Header wie class TextBlock {... gefolgt von einer statischen Zeichenfolge, die automatisch aus der Ressourcendatei generiert wird
  4. Erstellen Sie die generierte Java-Datei mit dem Rest Ihres Codes
horace
quelle
2

Wenn eine lange Reihe von + verwendet wird, wird nur ein StringBuilder erstellt, es sei denn, der String wird zur Kompilierungszeit festgelegt. In diesem Fall wird kein StringBuilder verwendet!

StringBuilder ist nur dann effizienter, wenn mehrere Anweisungen zum Erstellen des Strings verwendet werden.

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

Hinweis: Es wird nur ein StringBuilder erstellt.

  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

Um meine Frage weiter zu klären, mache ich mir überhaupt keine Sorgen um die Leistung. Ich mache mir Sorgen um Wartbarkeit und Designprobleme.

Machen Sie es so klar und einfach wie möglich.

Peter Lawrey
quelle