Chaîne multiligne Java


516

Venant de Perl, il me manque certainement le moyen "ici-document" de créer une chaîne multi-lignes dans le code source:

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

En Java, je dois avoir des guillemets encombrants et des signes plus sur chaque ligne pendant que je concatène ma chaîne multiligne à partir de zéro.

Quelles sont les meilleures alternatives? Définir ma chaîne dans un fichier de propriétés?

Edit : Deux réponses disent que StringBuilder.append () est préférable à la notation plus. Quelqu'un pourrait-il expliquer pourquoi ils le pensent? Cela ne me semble pas du tout préférable. Je cherche un moyen de contourner le fait que les chaînes multilignes ne sont pas une construction de langage de première classe, ce qui signifie que je ne veux certainement pas remplacer une construction de langage de première classe (concaténation de chaînes avec plus) par des appels de méthode.

Edit : Pour clarifier davantage ma question, je ne suis pas du tout préoccupé par les performances. Je suis préoccupé par les problèmes de maintenabilité et de conception.


12
StringBuilder.append () est préférable à plus lors de l'ajout répété à une chaîne, car à chaque fois que string1 + string2vous allouez un nouvel objet chaîne et copiez les caractères des deux chaînes d'entrée. Si vous ajoutez n chaînes ensemble, vous feriez n-1 allocations et environ (n ^ 2) / 2 copies de caractères. StringBuilder, en revanche, copie et réaffecte moins fréquemment (bien qu'il fasse toujours les deux lorsque vous dépassez la taille de son tampon interne). Théoriquement, il y a des cas où le compilateur pourrait convertir + pour utiliser StringBuilder mais en pratique qui sait.
Laurence Gonsalves

5
Chaque fois que je saute dans le débogueur, + est converti en un appel StringBuilder.append (), sur Java 1.5. Des collègues m'ont dit confusément que StringBuilder avait un bogue, car ils déboguaient dans du code qui ne semble pas l'appeler et se retrouvaient là.
skiphoppy


61
Notez qu'un littéral de chaîne composé de "abc \ n" + "def \ n" etc. n'utilise pas StringBuilder: le compilateur les colle ensemble et les place dans le fichier .class comme un littéral unique, comme avec les autres types de pliage constant.
araqnid,

6
La plupart des IDE prennent en charge la saisie de chaînes multi-lignes. c'est à dire. il vous suffit de taper ou de coller ce que vous voulez dans une "" chaîne et il ajoutera les \ n et "+" comme requis. par exemple, je peux coller 40 lignes de texte dans une chaîne et l'IDE le trie pour vous.
Peter Lawrey

Réponses:


118

Stephen Colebourne a créé une proposition pour ajouter des chaînes multilignes dans Java 7.

De plus, Groovy prend déjà en charge les chaînes multi-lignes .


14
Le processus Project Coin pour les améliorations de Java comprenait des chaînes de plusieurs lignes mail.openjdk.java.net/pipermail/coin-dev/2009-F February/… . Il a été rejeté par Oracle blogs.sun.com/darcy/entry/project_coin_final_five .
JodaStephen

8
un changement en 2012?
Ilia G

13
Malheureusement, cela ne semble pas avoir fait partie des spécifications.
namuol

3
Le lien blogs.sun.com est rompu, mais je pense que le contenu se trouve sur blogs.oracle.com/darcy/entry/project_coin_final_five maintenant.
Donal Fellows

8
Il semblerait qu'en janvier 2018, la communauté envisage de nouveau les chaînes multi-lignes. openjdk.java.net/jeps/326
Shane Gannon

485

Il semble que vous souhaitiez créer un littéral multiligne, qui n'existe pas en Java.

Votre meilleure alternative va être des cordes qui sont juste +ensemble. Certaines autres options que les gens ont mentionnées (StringBuilder, String.format, String.join) ne seraient préférables que si vous commenciez avec un tableau de chaînes.

Considère ceci:

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

Si vous voulez la nouvelle ligne pour votre système particulier, vous devez soit utiliser System.lineSeparator(), soit utiliser %ndans String.format.

Une autre option consiste à placer la ressource dans un fichier texte et à lire simplement le contenu de ce fichier. Ce serait préférable pour les très grandes chaînes pour éviter de gonfler inutilement vos fichiers de classe.


246
De plus, la première version sera automatiquement concaténée par le compilateur, puisque toutes les chaînes sont connues au moment de la compilation. Même si les chaînes ne sont pas connues au moment de la compilation, ce n'est pas plus lent que StringBuilder ou String.format (). La seule raison d'éviter la concaténation avec les + est si vous le faites en boucle.
Michael Myers

23
Le problème avec la String.formatversion est que vous devez synchroniser le format avec le nombre de lignes.
Bart van Heukelom

4
String.format n'est pas efficace par rapport aux deux autres exemples
cmcginty

10
Cette réponse est une solution très inappropriée à la question posée. Nous avons des macros SAS de 2000 lignes ou des groupes de requêtes SQL de 200 lignes que nous souhaitons copier et coller. Il est ridicule de suggérer que nous utilisons + "" concat pour transformer ces textes multilignes en appendices StringBuffer.
Blessed Geek

21
@BlessedGeek: la question était de savoir quelles options étaient disponibles dans le langage Java. Il ne mentionne rien sur le type de données entrant dans la chaîne. S'il existe une meilleure solution, vous pouvez la publier comme réponse. Il semble que la solution de Josh Curren serait meilleure pour votre situation. Si vous êtes simplement contrarié par le fait que la langue ne prend pas en charge les littéraux multilignes, ce n'est pas le bon endroit pour s'en plaindre.
Kip

188

Dans Eclipse, si vous activez l'option "Échapper le texte lors du collage dans un littéral de chaîne" (dans Préférences> Java> Éditeur> Saisie) et collez une chaîne à plusieurs lignes avec des guillemets, elle ajoutera automatiquement "et \n" +pour toutes vos lignes.

String str = "paste your text here";

15
intelij le fait également par défaut lorsque vous collez dans "" s
Bob B

Laissez-vous généralement dans le \rs qu'Eclipse met sous Windows?
Noumenon

99

C'est un vieux fil, mais une nouvelle solution assez élégante (avec seulement 4 peut-être 3 petits inconvénients) consiste à utiliser une annotation personnalisée.

Vérifier: http://www.adrianwalker.org/2011/12/java-multiline-string.html

Un projet inspiré de ce travail est hébergé sur GitHub:

https://github.com/benelog/multiline

Exemple de code Java:

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

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

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

Les inconvénients sont

  1. que vous devez activer le processeur d'annotation correspondant (fourni).
  2. cette variable String ne peut pas être définie comme variable locale Projet Check Raw String Literals où vous pouvez définir des variables comme variables locales
  3. cette chaîne ne peut pas contenir d'autres variables comme dans Visual Basic .Net avec XML literal ( <%= variable %>) :-)
  4. ce littéral de chaîne est délimité par un commentaire JavaDoc (/ **)

Et vous devrez probablement configurer Eclipse / Intellij-Idea pour ne pas reformater automatiquement vos commentaires Javadoc.

On peut trouver cela bizarre (les commentaires Javadoc ne sont pas conçus pour incorporer autre chose que des commentaires), mais comme ce manque de chaîne multiligne en Java est vraiment ennuyeux au final, je trouve que c'est la moins mauvaise solution.


Est-ce que cela nécessite que la classe utilisant la chaîne multiligne soit finale? De plus, une configuration est-elle requise lors du développement et de l'exécution de code à partir d'Eclipse? L'URL de référence mentionne les exigences de configuration de Maven pour le traitement des annotations. Je ne peux pas comprendre ce qui pourrait être nécessaire, le cas échéant, dans Eclipse.
David

L'annotation est vivable - mais il semble qu'il y ait également une forte dépendance à l'égard de maven? Cette partie enlève une grande partie de la valeur des hérédoc qui sont de simplifier la gestion des petits morceaux de texte.
javadba

3
Vous pouvez le faire entièrement en éclipse. Le lien que @SRG a posté ci-dessus vous pointe vers ce lien . Si vous utilisez eclipse, alors une minute de configuration et cela fonctionne.
Michael Plautz

4
C'est probablement le plus gros hack que j'ai jamais vu. EDIT: Nevermind ... voir la réponse de Bob Albrights.
Llew Vallis

1
J'ai fait une extension de ce projet et j'en ai créé une nouvelle dont les variables locales sont prises en charge, jetez un œil au projet
deFreitas

62

Une autre option peut être de stocker de longues chaînes dans un fichier externe et de lire le fichier dans une chaîne.


13
Exactement. De grandes quantités de texte n'appartiennent pas à la source Java; utilisez plutôt un fichier de ressources d'un format approprié, chargé via un appel à Class.getResource (String).
erickson

5
Droite! Vous pouvez également utiliser Locale + ResourceBundle pour charger facilement le texte I18N, puis l'appel String.format () analysera les "\ n" en tant que sauts de ligne :) Exemple: String readyStr = String.parse (resourceBundle.getString (" introduction"));
ATorras

62
Vous ne devriez pas avoir à externaliser une chaîne simplement parce qu'elle est multiligne. Que faire si j'ai une expression régulière que je souhaite décomposer en plusieurs lignes avec des commentaires? Ça a l'air moche en Java. La @syntaxe de C # est beaucoup plus propre.
Jeremy Stein

8
Skiphoppy ne veut pas se soucier de la surcharge de traitement des fichiers simplement pour utiliser une constante de chaîne de longueur de paragraphe. J'utilise tout le temps des chaînes multilignes en C ++, intégrées dans mon code source, là où je les veux.
Tim Cooper

9
Sensationnel. Je ne peux pas croire que C ++ soit en fait meilleur que Java sur ce problème! J'adore les constantes de chaîne multi-lignes et elles appartiennent à la source dans certains cas.
User1

59

C'est quelque chose que vous ne devriez jamais utiliser sans penser à ce qu'il fait. Mais pour des scripts uniques, j'ai utilisé cela avec beaucoup de succès:

Exemple:

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

15
Nécessite l'expédition du code Java pour la classe avec le binaire final. Hmm.
Thorbjørn Ravn Andersen

23
je peux imaginer la réaction de mes collègues quand j'essaye de vérifier quelque chose comme ça dans ...
Landon Kuhn

15
+1. Un certain manque d'imagination de la part des votants. Il s'agit d'une construction utile pour écrire de petits utilitaires, des cas de test et même dans des environnements de production contrôlés. C'est une différence entre abandonner Java dans ruby ​​/ python / etc ou rester ici.
javadba

1
Excellente solution, mais malheureusement, ne fonctionnera pas pour Android car elle sera exécutée sur émulateur ou appareil réel et il n'y a pas de code source.
evgeny.myasishchev

Peut-être que c'est un problème Java 8, ou autre chose, mais le classLoader dans l'exemple n'existe pas. J'ai essayé d'utiliser MyClass.class.getResourceAsStream (...), mais il retourne toujours null. Cela aurait été une excellente solution rapide pour les tests!
Nick

54

String.join

Java 8 a ajouté une nouvelle méthode statique à java.lang.Stringlaquelle offre une alternative légèrement meilleure:

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

En l'utilisant:

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

5
Solution nette et propre! Aucune dépendance à l'IDE et au préprocesseur! Aucun manuel "\n"n'est nécessaire, et est conscient de la portabilité!
Siu Ching Pong -Asuka Kenji-

1
Je comprends que mon commentaire est inutile, mais il est tellement recommencé à chercher des hacks pour une chose aussi basique qu'un littéral de chaîne multiligne. Pourquoi diable ne peut-il pas encore ajouter cela à la spécification?
dmitry


19

Si vous définissez vos chaînes dans un fichier de propriétés, la situation sera bien pire. IIRC, cela ressemblera à:

string:text\u000atext\u000atext\u000a

En règle générale, il est raisonnable de ne pas intégrer de grandes chaînes dans la source. Vous voudrez peut-être les charger en tant que ressources, peut-être au format XML ou dans un format texte lisible. Les fichiers texte peuvent être lus au moment de l'exécution ou compilés dans la source Java. Si vous finissez par les placer dans la source, je suggère de mettre +le devant et d'omettre les nouvelles lignes inutiles:

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

Si vous avez de nouvelles lignes, vous souhaiterez peut-être une méthode de jointure ou de formatage:

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

17

Les avantages sont convertis en StringBuilder.append, sauf lorsque les deux chaînes sont des constantes afin que le compilateur puisse les combiner au moment de la compilation. Du moins, c'est comme ça dans le compilateur de Sun, et je soupçonne que la plupart sinon tous les autres compilateurs feraient de même.

Donc:

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

génère normalement exactement le même code que:

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

D'autre part:

String c="Hello"+"Goodbye";

est le même que:

String c="HelloGoodbye";

Autrement dit, il n'y a pas de pénalité à casser vos littéraux de chaîne sur plusieurs lignes avec des signes plus pour la lisibilité.


4
pour être technique, dans votre premier exemple, il génère quelque chose de plus comme: String c = new StringBuilder (). append (a) .append (b) .toString (); La différence étant que le générateur de chaîne temporaire est hors de portée et éligible pour le ramasse-miettes immédiatement après la ligne String c = ..., tandis que le générateur de chaîne "temp" resterait un peu plus longtemps.
Kip

Vrai. Mon point, bien sûr, est de distinguer quand une fonction est appelée au moment de l'exécution par rapport au moment où le travail peut être effectué au moment de la compilation. Mais tu as raison.
Jay

15

Dans l'IDE IntelliJ, il vous suffit de taper:

""

Placez ensuite votre curseur à l'intérieur des guillemets et collez votre chaîne. L'IDE va ​​l'étendre en plusieurs lignes concaténées.


11

Malheureusement, Java n'a pas de littéraux de chaîne multi-lignes. Vous devez soit concaténer les littéraux de chaîne (en utilisant + ou StringBuilder étant les deux approches les plus courantes), soit lire la chaîne dans un fichier séparé.

Pour les grands littéraux de chaînes multi-lignes, je serais enclin à utiliser un fichier séparé et à le lire en utilisant getResourceAsStream()(une méthode de la Classclasse). Cela facilite la recherche du fichier car vous n'avez pas à vous soucier du répertoire actuel par rapport à l'emplacement d'installation de votre code. Cela facilite également l'empaquetage, car vous pouvez réellement stocker le fichier dans votre fichier jar.

Supposons que vous soyez dans une classe appelée Foo. Faites juste quelque chose comme ça:

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

Un autre inconvénient est que Java n'a pas de méthode standard "lire tout le texte de ce Reader dans une chaîne". C'est assez facile à écrire cependant:

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

Je fais la même chose. Vous pouvez utiliser commons-io pour lire plus facilement le contenu du fichier (avec "FileUtils.readFileToString (File file)").
SRG

Ce n'est plus vrai sur java n'a pas de méthode standard de lecture de tout le texte ... - depuis Java 7, vous pouvez utiliser Files.readAllLines (Path)
ccpizza

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

Mais, la meilleure alternative est d'utiliser String.format

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

À mon avis, il supprime les signes et les guillemets, ce qui le rend plus lisible, surtout lorsqu'il y a plus de 3 lignes. Pas aussi bon que String.format.
Tom

2
L'exemple de Stringbuilder est au moins aussi illisible. N'oubliez pas non plus que "\ n" n'est pas toujours une nouvelle ligne, mais c'est bien pour les machines Linux et Unix.
Stefan Thyberg,

De plus, je voulais juste mentionner l'existence de StringBuilder.
Tom

4
Remplacer un signe plus par un nom de méthode à six caractères et des parenthèses ne me semble pas plus lisible, même si apparemment vous n'êtes pas le seul à penser de cette façon. Cependant, cela ne supprime pas les guillemets. Ils sont toujours là.
skiphoppy

9

Étant donné que Java ne prend pas (encore) en charge les chaînes multilignes en mode natif, le seul moyen pour l'instant est de le contourner à l'aide de l'une des techniques susmentionnées. J'ai construit le script Python suivant en utilisant certaines des astuces mentionnées ci-dessus:

import sys
import string
import os

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

Mettez cela dans un fichier nommé javastringify.py et votre chaîne dans un fichier mystring.txt et exécutez-le comme suit:

cat mystring.txt | python javastringify.py

Vous pouvez ensuite copier la sortie et la coller dans votre éditeur.

Modifiez cela au besoin pour gérer tous les cas spéciaux, mais cela fonctionne pour mes besoins. J'espère que cela t'aides!


9

Vous pouvez utiliser le code scala, qui est compatible avec java, et autorise les chaînes multilignes entourées de "" ":

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

(notez les guillemets à l'intérieur de la chaîne) et de java:

String s2 = foobar.SWrap.bar ();

Que ce soit plus confortable ...?

Une autre approche, si vous manipulez souvent du texte long, qui doit être placé dans votre code source, pourrait être un script, qui prend le texte d'un fichier externe et l'enveloppe comme une chaîne java-multiligne comme ceci:

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

afin que vous puissiez le copier-coller facilement dans votre source.


8

Vous pouvez concaténer vos ajouts dans une méthode distincte comme:

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

Dans tous les cas, préférez StringBuilderla notation plus.


5
Pourquoi est-ce que je préfère StringBuilder à la notation plus?
skiphoppy

10
L'efficacité, ou plutôt une tentative souvent malavisée.
Michael Myers

2
La tentative d'efficacité est basée, je pense, sur le fait que le compilateur Java implémente l'opérateur de concaténation de chaînes à l'aide de StringBuilder (StringBuffer dans les compilateurs antérieurs à 1.5). Il existe un article ancien, mais bien connu, qui indique que l'utilisation de StringBuffer (ou StringBuilder, maintenant) présente des avantages en termes de performances. Voici le lien: java.sun.com/developer/JDCTechTips/2002/tt0305.html
Paul Morie

4
Seulement lorsque le compilateur ne peut pas le faire. Pour les littéraux et les constantes, si vous utilisez un signe plus, la concaténation est effectuée au moment de la compilation. L'utilisation d'un StringBuilder l'oblige à se produire au moment de l'exécution, donc ce n'est pas seulement plus de travail, c'est plus lent.
johncip

7

En fait, ce qui suit est la mise en œuvre la plus propre que j'ai vue jusqu'à présent. Il utilise une annotation pour convertir un commentaire en une variable chaîne ...

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

Ainsi, le résultat final est que la variable html contient la chaîne multiligne. Pas de guillemets, pas d'avantages, pas de virgules, juste une chaîne pure.

Cette solution est disponible à l'URL suivante ... http://www.adrianwalker.org/2011/12/java-multiline-string.html

J'espère que cela pourra aider!


Ce processeur d'annotations a besoin d'une vérification plus robuste,
Tripp Kinetics

J'aime ça. Essayer
javadba

7

Voir Java Stringfier . Transforme votre texte en un bloc java StringBuilder s'échappant si nécessaire.


1
Oui, car je peux passer ma vie à copier et coller sur ce site. Je pourrais également les stocker dans un fichier et les charger, mais ce n'est pas non plus une solution idéale.
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

Une alternative que je n'ai pas encore vue comme réponse est 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();

De plus, le fait d' java.io.BufferedWriteravoir une newLine()méthode n'est pas mentionné.


5

Si vous aimez la goyave de Google autant que moi, cela peut donner une représentation assez nette et un moyen agréable et facile de ne pas coder en dur vos caractères de nouvelle ligne aussi:

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

5

Utilisation Properties.loadFromXML(InputStream) . Il n'y a pas besoin de bibliothèques externes.

Mieux qu'un code en désordre (puisque la maintenabilité et la conception sont votre préoccupation), il est préférable de ne pas utiliser de longues chaînes.

Commencez par lire les propriétés xml:

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


alors vous pouvez utiliser votre chaîne multiligne de manière plus maintenable ...

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


MultiLine.xml` se trouve dans le même dossier 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: Vous pouvez utiliser <![CDATA["... "]]>pour une chaîne de type xml.


Oui, c'est ce que j'utilise également, excellente solution! Déplacez le SQL ou XML dans un fichier de propriétés XML externe. Il ne gâche pas le code. :)
Laszlo Lugosi

Cela ne répond pas à la question. les heredoc sont par définition dans le fichier . Le but est de le garder au même endroit.
javadba

5

Avec JDK / 12 Early Access Build # 12 , on peut désormais utiliser des chaînes multilignes en Java comme suit:

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

et cela se traduit par la sortie suivante:

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

Edit: reporté à java 13


1
Voici un moyen de l' essayer en utilisant maven
Naman

2
Comme le dit cybersoft dans d'autres commentaires, les littéraux de chaîne bruts (JEP326) ont été supprimés du JDK12 final, mais un autre JEP a été créé pour ajouter des "blocs de texte" qui peuvent être effectués en aperçu dans le JDK 13
Manuel Romeiro

4

Une solution assez efficace et indépendante de la plate-forme utiliserait la propriété système pour les séparateurs de lignes et la classe StringBuilder pour créer des chaînes:

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

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

    }

4

C'est une question très courante, j'ai donc décidé de transformer cette réponse en article également .

Java 13 et au-delà

Les chaînes multilignes sont désormais prises en charge en Java via les blocs de texte . En Java 13 et 14, cette fonctionnalité nécessite que vous définissiez l' ––enable–previewoption lors de la création et de l'exécution de votre projet. Consultez cette documentation Java pour plus de détails.

Maintenant, avant Java 13, voici comment vous écririez une requête:

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

Grâce aux blocs de texte Java 13, vous pouvez réécrire cette requête comme suit:

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

Beaucoup plus lisible, non?

Prise en charge IDE

IntelliJ IDEA prend en charge la transformation des Stringblocs de concaténation hérités au nouveau Stringformat multiligne :

Prise en charge des blocs de texte IntelliJ IDEA

JSON, HTML, XML

La multiligne String est particulièrement utile lors de l'écriture de JSON, HTML ou XML.

Considérez cet exemple en utilisant la Stringconcaténation pour créer un littéral de chaîne 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" +
        "       }" +
        "   ]" +
        "}"
    )
);

Vous pouvez à peine lire le JSON en raison des caractères qui s'échappent et de l'abondance de guillemets doubles et de signes plus.

Avec Java Text Blocks, l'objet JSON peut être écrit comme ceci:

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

Depuis que j'ai utilisé C # en 2004, je voulais avoir cette fonctionnalité en Java, et maintenant nous l'avons enfin.


3

Définir ma chaîne dans un fichier de propriétés?

Les chaînes multilignes ne sont pas autorisées dans les fichiers de propriétés. Vous pouvez utiliser \ n dans les fichiers de propriétés, mais je ne pense pas que ce soit une bonne solution dans votre cas.


La valeur dans un fichier de propriétés peut s'étendre sur plusieurs lignes: il suffit de terminer toutes les lignes sauf la dernière avec une barre oblique inverse. Cela laisse le problème de ce que vous utilisez comme séparateur de ligne, car cela est spécifique à la plate-forme. Je suppose que vous pourriez utiliser un simple \ n puis dans votre code, après avoir lu la propriété, faire une recherche et un remplacement de \ n dans line.separator. Cela semble un peu compliqué, mais je suppose que vous pourriez écrire une fonction qui récupère une propriété et effectue cette manipulation en même temps. Eh bien, tout cela suppose que vous écririez ces chaînes dans un fichier, ce qui est une grande hypothèse.
Jay


3

Je suggère d'utiliser un utilitaire tel que suggéré par ThomasP, puis de le lier à votre processus de construction. Un fichier externe est toujours présent pour contenir le texte, mais le fichier n'est pas lu au moment de l'exécution. Le workflow est alors:

  1. Construisez un utilitaire `` fichier texte en code java '' et vérifiez le contrôle de version
  2. Sur chaque build, exécutez l'utilitaire sur le fichier de ressources pour créer une source java révisée
  3. La source Java contient un en-tête comme class TextBlock {... suivi d'une chaîne statique qui est générée automatiquement à partir du fichier de ressources
  4. Construisez le fichier java généré avec le reste de votre code

2

Lorsqu'une longue série de + est utilisée, un seul StringBuilder est créé, sauf si la chaîne est déterminée au moment de la compilation, auquel cas aucun StringBuilder n'est utilisé!

Le seul moment où StringBuilder est plus efficace est lorsque plusieurs instructions sont utilisées pour construire la chaîne.

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

Remarque: Un seul StringBuilder est créé.

  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

Pour clarifier davantage ma question, je ne suis pas du tout préoccupé par la performance. Je suis préoccupé par les problèmes de maintenabilité et de conception.

Soyez aussi clair et simple que possible.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.