Chaîne multiligne Java


Venant de Perl, il me manque certainement le moyen "here-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 car 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 StringBuilder.append () est préférable à la notation plus. Quelqu'un pourrait-il dire pourquoi ils pensent ainsi? Cela ne me semble pas plus préférable du tout. 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.

Author: skiphoppy, 2009-05-18

30 answers

Stephen Colebourne a créé uneproposition pour ajouter des chaînes multi-lignes dans Java 7.

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

 95
Author: Paul Morie, 2017-12-01 12:34:43

On dirait que vous voulez faire un littéral multiligne, qui n'existe pas en Java.

Votre meilleure alternative va être des chaînes qui sont juste +'d ensemble. Quelques autres options que les gens ont mentionnées (StringBuilder, String.format de Chaîne de caractères.join) ne serait préférable que si vous avez commencé avec un tableau de chaînes.

Considérez 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";

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

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

Contre 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 que le saut de ligne à votre système, vous devez soit utiliser System.getProperty("line.separator"), ou vous pouvez utiliser %n dans String.format.

Une autre option consiste à placer la ressource dans un fichier texte et à simplement lire 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.

 405
Author: Kip, 2016-02-24 01:42:35

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 > Typage) et collez une chaîne multiligne entre guillemets, elle ajoutera automatiquement " et \n" + pour toutes vos lignes.

String str = "paste your text here";
 180
Author: Monir, 2011-12-22 15:29:06

C'est un vieux thread, mais une nouvelle solution assez élégante (avec un seul inconvénient) consiste à utiliser une annotation personnalisée.

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

Edit: L'URL ci-dessus semble être rompu. Un projet inspiré de ce travail est hébergé sur GitHub:

Https://github.com/benelog/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);
  }
}

L'inconvénient est que vous devez activer l'annotation correspondante (fournie) processeur.

Et vous devez probablement configurer Eclipse pour ne pas reformater automatiquement vos commentaires Javadoc.

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

 83
Author: SRG, 2018-09-27 18:53:24

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

 55
Author: Josh Curren, 2009-05-18 16:38:29

C'est quelque chose que vous ne devriez jamais utiliser sans penser à ce qu'il fait. Mais pour les scripts ponctuels, je l'ai utilisé 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();
}
 42
Author: Bob Albright, 2009-11-03 15:55:30

String.join

Java 8 a ajouté une nouvelle méthode statique à java.lang.String qui 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!"
);
 35
Author: icza, 2017-07-22 23:11:16

Si vous définissez vos chaînes dans un fichier de propriétés, cela aura l'air bien pire. IIRC, ça ressemblera à:

string:text\u000atext\u000atext\u000a

Généralement, c'est une idée raisonnable de ne pas intégrer de grandes chaînes à la source. Vous voudrez peut-être les charger en tant que ressources, peut-être en XML ou dans un format de texte lisible. Les fichiers texte peuvent être lus lors de l'exécution ou compilés dans Java source. Si vous finissez par les placer dans la source, je suggère de mettre le {[3] } à l'avant et d'omettre de nouvelles lignes inutiles:

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

Si vous le faites avoir de nouvelles lignes, vous voudrez peut-être une partie de la méthode de jointure ou de formatage:

final String text = join("\r\n"
    ,"text"
    ,"text"
    ,"text"
);
 19
Author: Tom Hawtin - tackline, 2009-05-18 16:47:43

Les avantages sont convertis en StringBuilder.ajouter, sauf lorsque les deux chaînes sont des constantes afin que le compilateur puisse les combiner au moment de la compilation. Au moins, c'est comme ça dans le compilateur de Sun, et je soupçonnerais 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";

C'est-à-dire qu'il n'y a aucune pénalité à casser vos littéraux de chaîne plusieurs lignes avec des signes plus pour la lisibilité.

 17
Author: Jay, 2009-05-19 00:37:21

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

""

Placez ensuite votre curseur à l'intérieur des guillemets et collez votre chaîne. L'EDI le développera en plusieurs lignes concaténées.

 12
Author: nurettin, 2016-10-08 16:28:13
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);
 10
Author: Tom, 2011-12-22 15:08:03

Malheureusement, Java n'a pas de littéraux de chaîne multi-lignes. Vous devez soit concaténer des 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 classe Class). Cela facilite la recherche du fichier car vous n'avez pas à vous soucier du répertoire actuel par rapport à l'endroit où votre code a été installé. Cela facilite également l'emballage, car vous pouvez réellement stocker le fichier dans votre fichier jar.

Supposons que vous soyez dans une classe appelée Foo. Faites simplement quelque chose comme ceci:

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

Le seul autre ennui est que Java n'a pas de méthode standard "lire tout le texte de ce lecteur 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();
}
 9
Author: Laurence Gonsalves, 2009-05-18 22:53:50

Étant donné que Java ne prend pas (encore) en charge les chaînes multi-lignes, la seule façon pour l'instant est de le pirater en utilisant 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. Espérons que cette aide!

 9
Author: scorpiodawg, 2011-02-21 18:22:12

Vous pouvez utiliser scala-code, qui est compatible avec java, et permet des 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 ();

Si c'est plus confortable ...?

Une autre approche, si vous gérez souvent du texte long, qui devrait ê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 couper et coller facilement dans votre source.

 9
Author: user unknown, 2017-06-20 16:28:25

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

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

Donc, le résultat final est que la variable html contient la chaîne multiligne. Pas de guillemets, pas plus, pas de virgule, juste la chaîne.

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

J'espère que ça aide!

 7
Author: Rodney P. Barbati, 2014-07-14 01:32:44
    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
Author: Mykhaylo Adamovych, 2014-06-03 07:17:16

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

De toute façon, préférez StringBuilder à la notation plus.

 6
Author: user54579, 2017-07-06 15:57:46

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

 6
Author: Leo, 2017-07-25 12:08:06

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

Aussi le fait que java.io.BufferedWriter a un newLine() méthode est passé sous silence.

 5
Author: BalusC, 2009-11-03 16:06:24

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

String out = Joiner.on(newline).join(ImmutableList.of(
    "line1",
    "line2",
    "line3"));
 5
Author: Dan Lo Bianco, 2012-07-10 17:08:27

Une solution assez efficace et indépendante de la plate-forme utiliserait la propriété system for line separators et la classe StringBuilder pour construire 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
Author: Andreas_D, 2014-05-25 18:26:14
 4
Author: alostale, 2018-10-01 11:10:02

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 solution dans votre cas.

 3
Author: Kip, 2009-05-18 16:43:20

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

    }
 3
Author: Bruno Marinho, 2016-05-18 02:38:15

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 la maintenabilité et la conception question.

Rendez-le aussi clair et simple que possible.

 2
Author: Peter Lawrey, 2009-05-19 19:39:01

Un petit tour. En utilisant cela, j'injecte javascritp dans une page HTML créée dynamiquement

StringBuilder builder = new StringBuilder();

public String getString()
{
    return builder.toString();
}
private DropdownContent _(String a)
{
    builder.append(a);
    return this;
}

public String funct_showhide()
{
   return
    _("function slidedown_showHide(boxId)").
    _("{").
    _("if(!slidedown_direction[boxId])slidedown_direction[boxId] = 1;").
    _("if(!slideDownInitHeight[boxId])slideDownInitHeight[boxId] = 0;").
    _("if(slideDownInitHeight[boxId]==0)slidedown_direction[boxId]=slidedownSpeed; ").
    _("else slidedown_direction[boxId] = slidedownSpeed*-1;").
    _("slidedownContentBox = document.getElementById(boxId);").
    _("var subDivs = slidedownContentBox.getElementsByTagName('DIV');").
    _("for(var no=0;no<subDivs.length;no++){").
    _(" if(subDivs[no].className=='dhtmlgoodies_content')slidedownContent = subDivs[no];").
    _("}").
    _("contentHeight = slidedownContent.offsetHeight;").
    _("slidedownContentBox.style.visibility='visible';").
    _("slidedownActive = true;").
    _("slidedown_showHide_start(slidedownContentBox,slidedownContent);").
    _("}").getString();

}
 2
Author: Hector Caicedo, 2010-12-12 18:39:44

Late model JAVA a des optimisations pour + avec des chaînes constantes, utilise un StringBuffer dans les coulisses, donc vous ne voulez pas encombrer votre code avec.

Il pointe vers un oubli JAVA, qu'il ne ressemble pas à ANSI C dans la concaténation automatique de chaînes entre guillemets doubles avec seulement un espace blanc entre elles, par exemple:

const char usage = "\n"
"Usage: xxxx <options>\n"
"\n"
"Removes your options as designated by the required parameter <options>,\n"
"which must be one of the following strings:\n"
"  love\n"
"  sex\n"
"  drugs\n"
"  rockandroll\n"
"\n" ;

J'aimerais avoir une constante de tableau de caractères multi-lignes où les linefeeds intégrés sont honorés, afin que je puisse présenter le bloc sans aucun encombrement, par exemple:

String Query = "
SELECT
    some_column,
    another column
  FROM
      one_table a
    JOIN
      another_table b
    ON    a.id = b.id
      AND a.role_code = b.role_code
  WHERE a.dept = 'sales'
    AND b.sales_quote > 1000
  Order BY 1, 2
" ;

Pour obtenir cela, il faut battre les dieux JAVA.

 2
Author: David Pickett, 2013-04-01 17:40:23

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

Mieux qu'un code désordonné (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);


ensuite, vous pouvez utiliser votre chaîne multiligne d'une manière plus maintenable...

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


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

 2
Author: jpfreire, 2018-02-26 19:43:19

Je sais que c'est une vieille question, mais pour les développeurs intersted, les littéraux multi-lignes vont être dans # Java12

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

 2
Author: Morteza Adi, 2018-07-07 22:15:30

Je suggère d'utiliser un utilitaire comme 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 flux de travail est alors:

  1. Créer un utilitaire 'textfile to java code' et vérifier dans le contrôle de version
  2. À 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é automatiquement à partir du fichier de ressources
  4. Construisez le fichier java généré avec le reste de votre code
 2
Author: horace, 2018-07-27 13:02:59