Stringa multilinea Java


516

Proveniente da Perl, mi manca sicuramente il mezzo "here-document" per creare una stringa multilinea nel codice sorgente:

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

In Java, devo avere virgolette ingombranti e segni più su ogni riga mentre concateno la mia stringa multilinea da zero.

Quali sono alcune alternative migliori? Definire la mia stringa in un file delle proprietà?

Modifica : due risposte dicono che StringBuilder.append () è preferibile alla notazione più. Qualcuno potrebbe spiegare il motivo per cui la pensano così? Non mi sembra più preferibile. Sto cercando un modo per aggirare il fatto che le stringhe multilinea non sono un costrutto di linguaggio di prima classe, il che significa che sicuramente non voglio sostituire un costrutto di linguaggio di prima classe (concatenazione di stringhe con più) con chiamate di metodo.

Modifica : per chiarire ulteriormente la mia domanda, non sono affatto preoccupato per le prestazioni. Sono preoccupato per manutenibilità e problemi di progettazione.


12
StringBuilder.append () è preferibile aggiungere più quando si aggiunge ripetutamente a una stringa perché ogni volta che string1 + string2si allocano un nuovo oggetto stringa e si copiano i caratteri da entrambe le stringhe di input. Se aggiungi n stringhe insieme, eseguiresti n-1 allocazioni e circa (n ^ 2) / 2 copie di caratteri. StringBuilder, d'altra parte, copia e rialloca meno frequentemente (anche se fa comunque entrambe le cose quando si supera la dimensione del suo buffer interno). Teoricamente, ci sono casi in cui il compilatore potrebbe convertire + per usare StringBuilder ma in pratica chi lo sa.
Laurence Gonsalves,

5
Ogni volta che salto nel debugger, + viene convertito in una chiamata StringBuilder.append (), su Java 1.5. Ho avuto dei colleghi confusamente dirmi che StringBuilder ha un bug dal momento che eseguono il debug in codice che non sembra chiamarlo e finisce lì.
skiphoppy,


61
Nota che una stringa letterale composta da "abc \ n" + "def \ n" ecc. Non usa StringBuilder: il compilatore li incolla e li inserisce nel file .class come un singolo letterale, come con altri tipi di piegatura costante.
araqnid,

6
La maggior parte degli IDE supporta l'immissione di stringhe multilinea. vale a dire. basta digitare o incollare ciò che si desidera in una "" stringa e aggiungerà \ n e "+" come richiesto. ad esempio, posso incollare 40 righe di testo in una stringa e l'IDE lo ordina per te.
Peter Lawrey,

Risposte:


118

Stephen Colebourne ha creato una proposta per l'aggiunta di stringhe multilinea in Java 7.

Inoltre, Groovy ha già il supporto per stringhe multilinea .


14
Il processo di Project Coin per i miglioramenti a Java includeva stringhe multilinea mail.openjdk.java.net/pipermail/coin-dev/2009-February/… . È stato rifiutato da Oracle blogs.sun.com/darcy/entry/project_coin_final_five .
JodaStephen,

8
qualche cambiamento nel 2012?
Ilia G,

13
Sfortunatamente questo non sembra averlo inserito nelle specifiche.
namuol,

3
Il link blogs.sun.com è interrotto, ma penso che il contenuto sia su blogs.oracle.com/darcy/entry/project_coin_final_five ora.
Donal Fellows,

8
Sembra, a partire da gennaio 2018, la community sta riconsiderando le stringhe multilinea. openjdk.java.net/jeps/326
Shane Gannon

485

Sembra che tu voglia fare un letterale multilinea, che non esiste in Java.

La tua migliore alternativa saranno le stringhe che sono solo +insieme. Alcune altre opzioni citate dalla gente (StringBuilder, String.format, String.join) sarebbero preferibili solo se avessi iniziato con una matrice di stringhe.

Considera questo:

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

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

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

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

Se si desidera che la nuova riga per il sistema particolare, si sia bisogno di usare System.lineSeparator(), oppure è possibile utilizzare %nin String.format.

Un'altra opzione è quella di mettere la risorsa in un file di testo e leggere semplicemente il contenuto di quel file. Questo sarebbe preferibile per stringhe molto grandi per evitare di gonfiare inutilmente i file di classe.


246
Inoltre, la prima versione verrà automaticamente concatenata dal compilatore, poiché tutte le stringhe sono note al momento della compilazione. Anche se le stringhe non sono note al momento della compilazione, non è più lenta di StringBuilder o String.format (). L'unico motivo per evitare la concatenazione con + è se lo fai in un ciclo.
Michael Myers

23
Il problema con la String.formatversione è che devi mantenere il formato sincronizzato con il numero di righe.
Bart van Heukelom,

4
String.format non è efficace rispetto ad altri due esempi
cmcginty il

10
Questa risposta è una soluzione molto inappropriata alla domanda in corso. Disponiamo di macro SAS a 2000 righe o gruppi di query SQL a 200 righe che desideriamo copiare e incollare. Suggerire di usare + "" concat per trasformare questi testi multilinea in StringBuffer aggiunge è ridicolo.
Beato Geek,

21
@BlessedGeek: la domanda a portata di mano era su quali opzioni erano disponibili nel linguaggio Java. Non ha menzionato nulla sul tipo di dati che vanno nella stringa. Se esiste una soluzione migliore, puoi pubblicarla come risposta. Sembra che la soluzione di Josh Curren sarebbe migliore per la tua situazione. Se sei solo sconvolto dal fatto che la lingua non supporti i letterali multilinea, questo è il posto sbagliato in cui lamentarti.
Kip

188

In Eclipse se si attiva l'opzione "Esci dal testo quando si incolla in una stringa letterale" (in Preferenze> Java> Editor> Digitazione) e si incolla una stringa a più righe tra virgolette, si aggiungerà automaticamente "e \n" +per tutte le linee.

String str = "paste your text here";

15
intelij lo fa anche di default quando incolli in "" s
Bob B il

Di solito lasci nelle \rs che Eclipse inserisce su Windows?
Noumenon,

99

Questo è un vecchio thread, ma una nuova soluzione abbastanza elegante (con solo 4 forse 3 piccoli inconvenienti) è quella di utilizzare un'annotazione personalizzata.

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

Un progetto ispirato a quel lavoro è ospitato su GitHub:

https://github.com/benelog/multiline

Esempio di codice Java:

import org.adrianwalker.multilinestring.Multiline;
...
public final class MultilineStringUsage {

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

  public static void main(final String[] args) {
    System.out.println(html);
  }
}

Gli svantaggi sono

  1. che devi attivare il corrispondente (fornito) processore di annotazione.
  2. quella variabile String non può essere definita come variabile locale Controlla il progetto Raw String Literals dove puoi definire variabili come variabili locali
  3. quella stringa non può contenere altre variabili come in .Net di Visual Basic con XML letterale ( <%= variable %>) :-)
  4. quel valore letterale String è delimitato dal commento JavaDoc (/ **)

E probabilmente devi configurare Eclipse / Intellij-Idea per non riformattare automaticamente i tuoi commenti Javadoc.

Si potrebbe trovare questo strano (i commenti di Javadoc non sono progettati per incorporare nient'altro che commenti), ma poiché questa mancanza di stringa multilinea in Java alla fine è davvero fastidiosa, trovo che questa sia la soluzione meno peggiore.


Ciò richiede che la classe che utilizza la stringa multilinea sia definitiva? Inoltre, è necessaria una configurazione per lo sviluppo e l'esecuzione del codice da Eclipse? L'URL di riferimento menziona i requisiti di configurazione per Maven per l'elaborazione delle annotazioni. Non riesco a capire cosa potrebbe essere necessario, se presente in Eclipse.
David,

L'annotazione è vivibile - ma sembra che ci sia stata anche una forte dipendenza da Maven? Quella parte toglie gran parte del valore delle eredità che servono a semplificare la gestione di piccoli pezzi di testo.
javadba,

3
Puoi farlo interamente in eclissi. Il link che @SRG ha pubblicato sopra ti fa riferimento a questo link . Se stai usando eclipse, quindi un minuto di installazione e funziona.
Michael Plautz,

4
Questo è probabilmente il più grande hack che abbia mai visto. EDIT: Nevermind ... vedi la risposta di Bob Albrights.
Llew Vallis,

1
Ho fatto un'estensione di questo progetto e ne ho creato uno nuovo con le variabili locali supportate, dai un'occhiata al progetto
deFreitas,

62

Un'altra opzione potrebbe essere quella di archiviare stringhe lunghe in un file esterno e leggere il file in una stringa.


13
Esattamente. Grandi quantità di testo non appartengono all'origine Java; utilizzare invece un file di risorse di un formato appropriato, caricato tramite una chiamata a Class.getResource (String).
Erickson,

5
Giusto! Puoi usare Locale + ResourceBundle anche per caricare facilmente il testo I18N, e quindi la chiamata String.format () analizzerà le "\ n" come nuove righe :) Esempio: String readyStr = String.parse (resourceBundle.getString (" introduzione"));
ATorras,

62
Non dovresti esternalizzare una stringa solo perché è multilinea. Cosa succede se ho una regex che voglio suddividere in più righe con commenti? Sembra brutto in Java. La @sintassi per C # è molto più pulita.
Jeremy Stein,

8
Skiphoppy non vuole preoccuparsi del sovraccarico di gestire i file solo per usare una costante di stringa di lunghezza di paragrafo. Uso sempre stringhe multilinea in C ++, integrate nel mio codice sorgente, dove le voglio.
Tim Cooper,

9
Wow. Non riesco a credere che C ++ sia effettivamente migliore di Java su questo problema! Adoro le costanti di stringa multilinea e in alcuni casi appartengono alla fonte.
Utente1

59

Questo è qualcosa che non dovresti mai usare senza pensare a cosa sta facendo. Ma per gli script una tantum l'ho usato con grande successo:

Esempio:

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

Codice:

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

15
Richiede la spedizione del codice Java per la classe con il file binario finale. Hmm.
Thorbjørn Ravn Andersen,

23
posso immaginare la mia reazione dei colleghi quando provo a controllare qualcosa del genere in ...
Landon Kuhn,

15
+1. Qualche mancanza di immaginazione da parte delle persone che votano verso il basso. Questo è un costrutto utile per scrivere piccole utility, casi di test e persino in ambienti di produzione controllati. Questa è una differenza tra abbandonare java in ruby ​​/ python / etc o rimanere qui.
javadba,

1
Ottima soluzione, ma sfortunatamente non funzionerà per Android poiché verrà eseguito su emulatore o dispositivo reale e non c'è codice sorgente lì.
evgeny.myasishchev

Forse è un prob Java 8, o qualcos'altro, ma il classLoader nell'esempio non esiste. Ho provato a utilizzare MyClass.class.getResourceAsStream (...), ma restituisce sempre null. Sarebbe stata un'ottima soluzione rapida per i test!
Nick,

54

String.join

Java 8 ha aggiunto un nuovo metodo statico al java.lang.Stringquale offre un'alternativa leggermente migliore:

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

Usandolo:

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

5
Soluzione pulita e ordinata! Nessuna dipendenza da IDE e preprocessore! Non "\n"è necessario alcun manuale ed è a conoscenza della portabilità!
Siu Ching Pong -Asuka Kenji-

1
Capisco che il mio commento sia inutile, ma è così ricominciato a cercare hack per una cosa di base come una stringa multilinea letterale. Perché diamine non può java ancora aggiungere questo nelle specifiche?
Dmitry,

22

JEP 355: Text Blocks (Anteprima) ha lo scopo di coprire questa funzionalità, attualmente è destinato a JDK 13 come funzionalità di anteprima. Permettere di scrivere qualcosa del tipo:

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

Precedentemente a questo JEP, in JDK12, JEP 326: Raw String Literals mirava a implementare una funzione simile, ma alla fine è stata ritirata.


2
Hanno abbandonato questo supporto
deFreitas il

2
I blocchi di testo fanno ora parte di Java 13.
ZhekaKozlov,

19

Se definisci le tue stringhe in un file delle proprietà, sembrerà molto peggio. IIRC, assomiglierà a:

string:text\u000atext\u000atext\u000a

Generalmente è un'idea ragionevole non incorporare stringhe di grandi dimensioni nel sorgente. Potresti caricarli come risorse, magari in XML o in un formato di testo leggibile. I file di testo possono essere letti in fase di esecuzione o compilati in sorgente Java. Se finisci per metterli nella fonte, ti suggerisco di mettere il+ in primo piano e omettere nuove righe non necessarie:

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

Se hai nuove righe, potresti voler un po 'di metodo di join o formattazione:

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

17

I plus vengono convertiti in StringBuilder.append, tranne quando entrambe le stringhe sono costanti in modo che il compilatore possa combinarle al momento della compilazione. Almeno, è così che è nel compilatore di Sun, e sospetterei di più se non tutti gli altri compilatori farebbero lo stesso.

Così:

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

normalmente genera esattamente lo stesso codice di:

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

D'altro canto:

String c="Hello"+"Goodbye";

equivale a:

String c="HelloGoodbye";

Cioè, non vi è alcuna penalità nel rompere i letterali di stringa su più righe con segni più per la leggibilità.


4
per essere tecnico, nel tuo primo esempio genera qualcosa di più simile a: String c = new StringBuilder (). append (a) .append (b) .toString (); La differenza è che il generatore di stringhe temporaneo è fuori dall'ambito e idoneo per la garbage collection immediatamente dopo la riga String c = ..., mentre il generatore di stringhe "temp" rimarrebbe un po 'più a lungo.
Kip

Vero. Il mio punto, ovviamente, è distinguere quando una funzione viene chiamata in fase di esecuzione rispetto a quando il lavoro può essere eseguito in fase di compilazione. Ma hai ragione.
Jay,

15

Nell'IDE IntelliJ devi solo digitare:

""

Quindi posizionare il cursore tra virgolette e incollare la stringa. L'IDE lo espande in più righe concatenate.


11

Purtroppo, Java non ha valori letterali di stringa multilinea. Devi concatenare i valori letterali delle stringhe (usando + o StringBuilder sono i due approcci più comuni a questo) o leggere la stringa da un file separato.

Per i letterali con stringhe multilinea di grandi dimensioni sarei propenso a utilizzare un file separato e leggerlo usando getResourceAsStream()(un metodo diClass classe). Ciò semplifica la ricerca del file in quanto non è necessario preoccuparsi della directory corrente rispetto a dove è stato installato il codice. Inoltre semplifica il packaging, poiché è possibile archiviare effettivamente il file nel file jar.

Supponi di essere in una classe chiamata Foo. Fai qualcosa del genere:

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

L'altra seccatura è che Java non ha un metodo standard "leggi tutto il testo da questo Reader in una stringa". È abbastanza facile da scrivere però:

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

Faccio lo stesso. Puoi usare commons-io per leggere più facilmente il contenuto del file (con "FileUtils.readFileToString (File file)").
SRG

Non è più vero su Java non ha un metodo standard per leggere tutto il testo ... - da Java 7 è possibile utilizzare Files.readAllLines (Path)
ccpizza,

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

Ma la migliore alternativa è usare String.format

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

La mia opinione è che rimuove i segni più e le virgolette, rendendolo più leggibile, specialmente quando ci sono più di sole 3 righe. Non buono come String.format però.
Tom,

2
L'esempio Stringbuilder è almeno illeggibile. Inoltre, non dimenticare che "\ n" non è sempre una newline, ma va bene per macchine linux e unix.
Stefan Thyberg,

Inoltre, volevo solo menzionare l'esistenza di StringBuilder.
Tom,

4
Sostituire un segno più con un nome di metodo di sei caratteri e parentesi non mi sembra più leggibile, anche se apparentemente non sei l'unico che la pensa così. Tuttavia, non rimuove le virgolette. Sono ancora lì.
skiphoppy,

9

Poiché Java non supporta (ancora) nativamente le stringhe multilinea, l'unico modo per ora è di hackerarlo utilizzando una delle tecniche sopra menzionate. Ho creato il seguente script Python usando alcuni dei trucchi sopra menzionati:

import sys
import string
import os

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

Inseriscilo in un file chiamato javastringify.py e la tua stringa in un file mystring.txt ed eseguilo come segue:

cat mystring.txt | python javastringify.py

È quindi possibile copiare l'output e incollarlo nel proprio editor.

Modificalo come necessario per gestire eventuali casi speciali, ma funziona per le mie esigenze. Spero che sia di aiuto!


9

È possibile utilizzare lo scala-code, che è compatibile con Java, e consente stringhe multilinea racchiuse con "" ":

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

(nota le virgolette all'interno della stringa) e da Java:

String s2 = foobar.SWrap.bar ();

Se questo è più comodo ...?

Un altro approccio, se gestisci spesso testo lungo, che dovrebbe essere inserito nel tuo codice sorgente, potrebbe essere uno script, che prende il testo da un file esterno e lo avvolge come una stringa java multilinea come questa:

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

in modo che tu possa tagliarlo e incollarlo facilmente nella tua fonte.


8

Puoi concatenare i tuoi allegati in un metodo separato come:

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

In entrambi i casi, preferisci StringBuilderalla notazione più.


5
Perché preferisco StringBuilder alla notazione più?
skiphoppy,

10
Efficienza, o piuttosto un tentativo spesso fuorviato.
Michael Myers

2
Il tentativo di efficienza si basa, credo, sul fatto che il compilatore Java implementa l'operatore di concatenazione di stringhe usando StringBuilder (StringBuffer nei compilatori pre-1.5). C'è un vecchio articolo, ma noto, che afferma che ci sono benefici prestazionali in determinate situazioni nell'uso di StringBuffer (o StringBuilder, ora). Ecco il link: java.sun.com/developer/JDCTechTips/2002/tt0305.html
Paul Morie,

4
Solo quando il compilatore non può farlo. Per letterali e costanti, se si utilizza un segno più, la concatenazione viene eseguita in fase di compilazione. L'uso di StringBuilder impone che avvenga in fase di esecuzione, quindi non è solo più lavoro, è più lento.
johncip

7

In realtà, la seguente è l'implementazione più pulita che ho visto finora. Usa un'annotazione per convertire un commento in una variabile stringa ...

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

Quindi, il risultato finale è che la variabile html contiene la stringa multilinea. Nessuna virgoletta, nessun vantaggio, nessuna virgola, solo una stringa pura.

Questa soluzione è disponibile al seguente URL ... http://www.adrianwalker.org/2011/12/java-multiline-string.html

Spero che aiuti!


Quel processore di annotazione necessita di un controllo più efficace,
Tripp Kinetics,

Mi piace questo. Provandolo
javadba

7

Vedi Java Stringfier . Trasforma il tuo testo in un blocco Java StringBuilder che fuoriesce se necessario.


1
Sì, perché posso passare la mia vita a copiare e incollare in quel sito. Potrei anche semplicemente memorizzarli in un file e caricarlo ma non è nemmeno una soluzione ideale.
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");

6

Un'alternativa che non ho ancora visto come risposta è la 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();

Anche il fatto che java.io.BufferedWriterabbia un newLine()metodo non è menzionato.


5

Se ti piace la guava di google tanto quanto me, può dare una rappresentazione abbastanza chiara e un modo semplice e piacevole per non codificare troppo i tuoi caratteri newline:

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

5

Uso Properties.loadFromXML(InputStream) . Non sono necessarie librerie esterne.

Meglio di un codice disordinato (poiché la manutenzione e il design sono la tua preoccupazione), è preferibile non utilizzare stringhe lunghe.

Inizia leggendo le proprietà xml:

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


allora puoi usare la tua stringa multilinea in un modo più gestibile ...

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


MultiLine.xml` si trova nella stessa cartella 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 .: Puoi usare <![CDATA[" ... "]]>per una stringa simile a xml.


Sì, è anche quello che uso, ottima soluzione! Spostare SQL o XML in un file di proprietà XML esterno. Non rovina il codice. :)
Laszlo Lugosi

Questo non risponde alla domanda. le eredità sono per definizione all'interno del file . Il punto è tenerlo in un posto.
javadba,

5

Con build # 12 di accesso anticipato JDK / 12 , ora è possibile utilizzare stringhe multilinea in Java come segue:

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

e questo si traduce nel seguente output:

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

Modifica: rinviato a java 13


1
Ecco un modo per provarlo usando Maven
Naman,

2
Come afferma cybersoft su altri commenti, i letterali non elaborati (JEP326) sono stati rimossi dal JDK12 finale, ma è stato creato un altro JEP per aggiungere "blocchi di testo" che possono essere eseguiti come anteprima in JDK 13
Manuel Romeiro

4

Una soluzione abbastanza efficiente e indipendente dalla piattaforma sarebbe usare la proprietà di sistema per i separatori di linea e la classe StringBuilder per costruire stringhe:

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

4

Una buona opzione.

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

    }

4

Questa è una domanda molto comune, quindi ho deciso di trasformare anche questa risposta in un articolo .

Java 13 e oltre

Le stringhe multilinea sono ora supportate in Java tramite blocchi di testo . In Java 13 e 14, questa funzione richiede di impostare il file––enable–preview opzione durante la creazione e l'esecuzione del progetto. Dai un'occhiata a questa documentazione Java per maggiori dettagli.

Ora, prima di Java 13, ecco come scrivere una 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();

Grazie a Java 13 Text Blocks, puoi riscrivere questa query come segue:

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

Molto più leggibile, vero?

Supporto IDE

IntelliJ IDEA fornisce supporto per la trasformazione dei Stringblocchi di concatenazione legacy nel nuovo Stringformato multilinea :

Supporto IntelliJ IDEA Text Blocks

JSON, HTML, XML

Il multilinea String è particolarmente utile quando si scrive JSON, HTML o XML.

Considera questo esempio usando la Stringconcatenazione per creare un valore letterale stringa JSON:

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

A malapena puoi leggere il JSON a causa dei caratteri di escape e dell'abbondanza di virgolette doppie e segni più.

Con Java Text Blocks, l'oggetto JSON può essere scritto in questo modo:

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

Da quando ho usato C # nel 2004, volevo avere questa funzione in Java, e ora finalmente ce l'abbiamo.


3

Definire la mia stringa in un file delle proprietà?

Le stringhe multilinea non sono consentite nei file delle proprietà. È possibile utilizzare \ n nei file delle proprietà, ma non credo che sia una soluzione nel tuo caso.


Il valore in un file delle proprietà può comprendere più righe: basta terminare tutte le righe tranne l'ultima con una barra rovesciata. Questo lascia il problema di ciò che si utilizza come separatore di linea, poiché è specifico della piattaforma. Suppongo che potresti usare un semplice \ n e quindi nel tuo codice, dopo aver letto la proprietà, fai una ricerca e sostituzione di \ n in line.separator. Sembra un po 'complicato, ma credo che potresti scrivere una funzione che recupera una proprietà e fa questa manipolazione allo stesso tempo. Bene, tutto ciò presuppone che tu stia scrivendo queste stringhe in un file, il che è un grande presupposto.
Jay,


3

Suggerisco di utilizzare un'utilità come suggerito da ThomasP, quindi collegarla al processo di compilazione. È ancora presente un file esterno per contenere il testo, ma il file non viene letto in fase di esecuzione. Il flusso di lavoro è quindi:

  1. Crea un'utilità "textfile to java code" e controlla il controllo versione
  2. Su ogni build, eseguire l'utilità sul file di risorse per creare una fonte java rivista
  3. Il sorgente Java contiene un'intestazione come class TextBlock {...seguita da una stringa statica che viene generata automaticamente dal file di risorse
  4. Crea il file java generato con il resto del codice

2

Quando viene utilizzata una lunga serie di +, viene creato un solo StringBuilder, a meno che String non venga determinato al momento della compilazione, nel qual caso non viene utilizzato StringBuilder!

L'unica volta in cui StringBuilder è più efficiente è quando vengono utilizzate più istruzioni per costruire String.

String a = "a\n";
String b = "b\n";
String c = "c\n";
String d = "d\n";

String abcd = a + b + c + d;
System.out.println(abcd);

String abcd2 = "a\n" +
        "b\n" +
        "c\n" +
        "d\n";
System.out.println(abcd2);

Nota: viene creato solo un StringBuilder.

  Code:
   0:   ldc     #2; //String a\n
   2:   astore_1
   3:   ldc     #3; //String b\n
   5:   astore_2
   6:   ldc     #4; //String c\n
   8:   astore_3
   9:   ldc     #5; //String d\n
   11:  astore  4
   13:  new     #6; //class java/lang/StringBuilder
   16:  dup
   17:  invokespecial   #7; //Method java/lang/StringBuilder."<init>":()V
   20:  aload_1
   21:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   24:  aload_2
   25:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   28:  aload_3
   29:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   32:  aload   4
   34:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   37:  invokevirtual   #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   40:  astore  5
   42:  getstatic       #10; //Field java/lang/System.out:Ljava/io/PrintStream;
   45:  aload   5
   47:  invokevirtual   #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   50:  ldc     #12; //String a\nb\nc\nd\n
   52:  astore  6
   54:  getstatic       #10; //Field java/lang/System.out:Ljava/io/PrintStream;
   57:  aload   6
   59:  invokevirtual   #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   62:  return

Per chiarire ulteriormente la mia domanda, non sono affatto preoccupato per le prestazioni. Sono preoccupato per manutenibilità e problemi di progettazione.

Rendilo il più chiaro e semplice possibile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.