607 votes

Chaîne multiligne en Java

Venant de Perl, je suis sûr que le moyen "here-document" pour créer une chaîne de plusieurs lignes dans le code source me manque :

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

En Java, je suis obligé d'avoir des guillemets et des signes plus encombrants sur chaque ligne lorsque 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 ?

Modifier : Deux réponses disent que StringBuilder.append() est préférable à la notation plus. Quelqu'un peut-il expliquer pourquoi il le pense ? 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 absolument pas remplacer une construction de langage de première classe (concaténation de chaînes avec plus) par des appels de méthode.

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

13 votes

StringBuilder.append() est préférable à plus lorsqu'il s'agit d'ajouter de manière répétée à une chaîne de caractères, car chaque fois que vous faites string1 + string2 vous 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 ferez n-1 allocations et approximativement (n^2)/2 copies de caractères. StringBuilder, d'autre part, copie et réalloue 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.

1 votes

Oups. La partie concernant les copies de caractères était un peu confuse/peu claire. Chaque caractère est copié une fois pour chaque chaîne qui le suit dans la concaténation. Si toutes vos chaînes de caractères sont d'un seul caractère, vous obtenez approximativement (n^2)/2 copies de caractères. Il s'agit en fait de (n^2)/2 copies de chaînes, sauf que les dernières fois qu'une chaîne est copiée, elle l'est en même temps que les éléments auxquels elle a été jointe (mais le coût est proportionnel au nombre de caractères, donc compter les copies de chaînes est un peu trompeur). Pour faire court : le coût est approximativement quadratique, alors que StringBuilder essaie de rendre le coût amorti linéaire.

0 votes

Il y a un article sur ce sujet - j'ai ajouté un lien ci-dessous, mais le voici à nouveau : java.sun.com/developer/JDCTechTips/2002/tt0305.html

558voto

Kip Points 37013

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

Votre meilleure alternative est d'utiliser des cordes qui sont juste + ensemble. Les autres options mentionnées (StringBuilder, String.format, String.join) ne sont préférables que si vous commencez 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";

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 que la nouvelle ligne soit adaptée à votre système particulier, vous devez soit utiliser System.lineSeparator() ou vous pouvez utiliser %n sur String.format .

Une autre option est de placer la ressource dans un fichier texte, et de lire simplement le contenu de ce fichier. Cette solution est préférable pour les chaînes de caractères très volumineuses afin d'éviter d'alourdir inutilement vos fichiers de classe.

268 votes

De plus, la première version sera automatiquement concaténée par le compilateur, puisque toutes les chaînes de caractères 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 dans une boucle.

0 votes

Le StringBuilder est ce que j'ai vu (encore et encore) comme code maintenable et efficace. Le String.format est efficace, mais suffisamment rare pour les développeurs Java pour que la maintenabilité diminue.

27 votes

Le problème avec le String.format est que vous devez faire en sorte que le format soit synchronisé avec le nombre de lignes.

193voto

Monir Points 482

Dans Eclipse, si vous activez l'option "Escape text when pasting into a string literal" (dans Préférences > Java > Editeur > Typing) et que vous collez une chaîne de caractères à plusieurs lignes entre guillemets, le système ajoutera automatiquement les éléments suivants " et \n" + pour toutes vos lignes.

String str = "paste your text here";

19 votes

Intelij le fait aussi par défaut lorsque vous collez dans ""s"".

1 votes

Est-ce que vous laissez généralement dans le \r qu'Eclipse met en place sous Windows ?

123voto

Paul Morie Points 6956

Stephen Colebourne a créé un proposition pour ajouter des chaînes de caractères multi-lignes dans Java 7.

En outre, Groovy prend déjà en charge chaînes de caractères multi-lignes .

14 votes

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

14 votes

Malheureusement, cela ne semble pas avoir été intégré dans la spécification.

3 votes

Le lien vers blogs.sun.com est cassé, mais je pense que le contenu est à blogs.oracle.com/darcy/entry/project_coin_final_five maintenant.

102voto

SRG Points 796

Il s'agit d'un vieux sujet, mais une nouvelle solution assez élégante (avec seulement 4 ou 3 petits inconvénients) consiste à utiliser une annotation personnalisée.

Vérifiez : 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 les suivants

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

Et vous devez 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 intégrer autre chose que des commentaires), mais comme cette absence de chaîne de caractères multiligne en Java est vraiment ennuyeuse au final, je trouve que c'est la moins mauvaise des solutions.

0 votes

Est-ce que cela nécessite que la classe utilisant la chaîne de caractères multiligne soit finale ? Par ailleurs, une configuration est-elle nécessaire pour développer et exécuter du code à partir d'Eclipse ? L'URL de référence mentionne les exigences de configuration de Maven pour le traitement des annotations. Je n'arrive pas à comprendre ce qui est nécessaire, le cas échéant, dans Eclipse.

0 votes

L'annotation est vivable - mais il semble qu'il y ait aussi une dépendance dure sur maven ? Cette partie enlève une grande partie de la valeur des heredoc's qui sont de simplifier la gestion de petits morceaux de texte.

3 votes

Vous pouvez le faire entièrement dans Eclipse. Le lien que @SRG a posté ci-dessus vous dirige vers ce lien . Si vous utilisez eclipse, une minute de configuration et tout fonctionne.

66voto

Josh Curren Points 2993

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

15 votes

Exactement. Les grandes quantités de texte n'ont pas leur place dans les sources Java ; utilisez plutôt un fichier de ressources d'un format approprié, chargé via un appel à Class.getResource(String).

5 votes

C'est vrai ! Vous pouvez également utiliser Locale + ResourceBundle pour charger facilement le texte I18N, et ensuite l'appel String.format() analysera le " \n Les " comme nouvelles lignes :) Exemple : String readyStr = String.parse(resourceBundle.getString("introduction")) ;

69 votes

Vous ne devriez pas avoir à externaliser un String juste parce qu'il est multi-lignes. Et si j'ai une regex que je veux diviser en plusieurs lignes avec des commentaires ? C'est très laid en Java. Le site @ La syntaxe du C# est beaucoup plus propre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X