Pregunta

Viniendo de Perl, estoy seguro que estoy perdiendo el "aquí-documento" mediante la creación de una cadena de múltiples líneas de código fuente:

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

En Java, tengo que tener cotizaciones engorrosos y signos positivos en cada línea, ya que mi concatenar cadena de varias partir de cero.

¿Cuáles son algunas alternativas mejores? Definir mi cadena en un fichero de propiedades?

Editar : Dos respuestas dicen StringBuilder.append () es preferible a la notación más. ¿Alguien podría elaborar en cuanto a por qué piensan así? No se ve más preferible para mí en absoluto. Estoy buscando una manera de evitar el hecho de que las cadenas de varias líneas no son una construcción del lenguaje de primera clase, lo que significa que definitivamente no quiero reemplazar una construcción del lenguaje de primera clase (concatenación de cadenas con más) con llamadas a métodos.

Editar : Para aclarar aún más mi pregunta, no estoy preocupado por el rendimiento en absoluto. Estoy preocupado por los problemas de mantenimiento y diseño.

¿Fue útil?

Otros consejos

Parece que usted quiere hacer una línea múltiple literal, que no existe en Java.

Su mejor alternativa va a ser cadenas que son sólo +'d juntos. Algunas otras personas han mencionado Opciones (StringBuilder, String.Format, string.join) sólo sería preferible si usted empieza con una matriz de cadenas.

Considere esto:

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 desea que la nueva línea para su sistema particular, que sea necesario utilizar System.getProperty("line.separator"), o puede utilizar %n en String.format.

Otra opción es poner el recurso en un archivo de texto, y acaba de leer el contenido de ese archivo. Esto sería preferible para las grandes cadenas para evitar innecesariamente hinchazón de archivos de clases.

En Eclipse si activa la opción "Escape de texto al pegar en una cadena literal" (en Preferencias> Java> Editor> Typing) y pegar una cadena multi-revestido whithin cotizaciones, se añadirá automáticamente " y \n" + para todos sus líneas.

String str = "paste your text here";

Este es un viejo hilo, pero una nueva solución muy elegante (con sólo 4 quizás 3 pequeños inconvenientes) es utilizar una anotación personalizada.

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

Un proyecto inspirado en el trabajo que está alojado en GitHub:

https://github.com/benelog/multiline

Ejemplo de código 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);
  }
}

Los inconvenientes son

  1. que tiene que activar la anotación correspondiente (siempre) procesador.
  2. esa variable de cadena no se puede definir como Check variable local literales de cadena primas proyecto donde se pueden definir variables como variables locales
  3. esa cadena no se contiene otras variables como en Visual Basic .Net con el literal XML (<%= variable %>): -)
  4. literal de cadena que está delimitada por el comentario JavaDoc (/ **)

Y es probable que tenga que configurar Eclipse / IntelliJ Idea-a no volver a formatear automáticamente sus comentarios Javadoc.

Uno puede encontrar este extraño (comentarios Javadoc no están diseñados para incrustar aparte de los comentarios nada), pero a medida que esta falta de cadena de varias en Java es muy molesto al final, me parece que este es la solución menos mala.

Otra opción puede ser la de almacenar cadenas largas en un archivo externo y leer el archivo en una cadena.

Esto es algo que se debe hacer no uso sin pensar en lo que está haciendo. Pero para los scripts de una sola vez he utilizado esto con gran éxito:

Ejemplo:

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

Código:

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

String.join

Java 8 añade un nuevo método estático a java.lang.String que ofrece un poco mejor alternativa:

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

Su uso:

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

Si define sus cadenas en un archivo de propiedades que se verá mucho peor. IIRC, parecerá que:

string:text\u000atext\u000atext\u000a

En general se trata de una idea razonable de no incorporar grandes cadenas en la fuente. Es posible que desee cargar como recursos, tal vez en XML o un formato de texto legible. Los archivos de texto se pueden leer ya sea en tiempo de ejecución o compilados en fuente de Java. Si al final de colocarlos en la fuente, Sugiero poner el + en la parte delantera y omitiendo nuevas líneas innecesarias:

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

Si usted tiene nuevas líneas, es posible que desee unirse a algunos de formato o método:

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

Ventajas se convierten en StringBuilder.append, excepto cuando ambas cadenas son constantes por lo que el compilador puede combinarlos en tiempo de compilación. Al menos, eso es lo que pasa en el compilador de Sun, y yo sospecharía la mayoría si no todos los compiladores de otros harían lo mismo.

Así que:

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

normalmente genera exactamente el mismo código que:

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

Por otro lado:

String c="Hello"+"Goodbye";

es el mismo que:

String c="HelloGoodbye";

Es decir, no hay pena de romper sus cadenas literales a través de múltiples líneas con más signos para facilitar la lectura.

En el IDE IntelliJ sólo tiene que escribir:

""

A continuación, coloque el cursor dentro de las comillas y pegar su cadena. El IDE se expandirá en múltiples líneas concatenadas.

PEC 355: bloques de texto (vista previa) pretende cubrir esta funcionalidad, es actualmente la orientación JDK 13 como una característica de vista previa. Permitiendo a escribir algo como:

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

Antes de este PEC, en jdk12, PEC 326: primas literales de cadena destinado a poner en práctica una característica similar, pero finalmente fue retirada.

Lamentablemente, Java no tiene literales de cadena multilínea. Usted tiene que concatenar cadenas literales (usando + o StringBuilder siendo los dos enfoques más comunes para esto) o leer la cadena desde un archivo separado.

Para las grandes cadenas literales multilínea Estaría inclinado a usar un archivo separado y leerlo en el uso de getResourceAsStream() (un método de la clase Class). Esto hace que sea fácil encontrar el archivo que usted no tiene que preocuparse por el directorio actual en comparación con el que se instaló el código. También hace que el envasado más fácil, porque en realidad se puede almacenar el archivo en el archivo jar.

Supongamos que estás en una clase llamada Foo. Sólo hacer algo como esto:

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

La otra molestia es que Java no tiene un estándar de "leer todo el texto de este lector en una cadena" método. Es bastante fácil de escribir sin embargo:

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();
}
String newline = System.getProperty ("line.separator");
string1 + newline + string2 + newline + string3

Sin embargo, la mejor alternativa es utilizar String.Format

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

Dado que Java no (todavía) de soporte nativo cadenas multilínea, la única manera de que ahora es modificar su alrededor utilizando una de las técnicas antes mencionadas. Construí el siguiente script Python usando algunos de los trucos mencionados anteriormente:

import sys
import string
import os

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

Pon eso en un archivo llamado javastringify.py y su cadena en un mystring.txt archivo y ejecutarlo de la siguiente manera:

cat mystring.txt | python javastringify.py

A continuación, puede copiar y pegar la salida en su editor.

Modificar esta como sea necesario para manejar los casos especiales, pero esto funciona para mis necesidades. Esperamos que esto ayude!

Es posible utilizar scala-código, que es compatible con Java, y permite multilínea cuerdas cerrado con "" ":

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

(nótese las comillas dentro de la cadena) y de Java:

String s2 = foobar.SWrap.bar ();

Si esto es más cómodo ...?

Otro enfoque, si a menudo manejar texto largo, que debe ser colocado en su código fuente, podría ser un guión, que toma el texto de un archivo externo, y wrappes como una línea múltiple-java-cadena como esta:

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

para que pueda cortar y pegar fácilmente en su fuente.

Puede concatenar sus APPENDs en un método separado como:

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

De cualquier manera, prefieren StringBuilder a la notación más.

En realidad, la siguiente es la aplicación más limpio que he visto hasta ahora. Utiliza una anotación para convertir un comentario en una variable de cadena ...

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

Por lo tanto, el resultado final es que el html variable contiene la cadena de varias líneas. Sin comillas, no hay ventajas, sin comas, justo cadena pura.

Esta solución está disponible en la siguiente dirección ... http://www.adrianwalker.org/2011/12/java-multiline -string.html

Espero que ayude!

de Java Stringfier . Convierte su texto en un bloque de StringBuilder java escapar si es necesario.

Una alternativa que no he visto como respuesta todavía es el 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();

También el hecho de que java.io.BufferedWriter tiene un método newLine() no se menciona.

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

Si te gusta la guayaba de Google tanto como lo hacen, puede dar una representación bastante limpio y una buena manera, no fácil de codificar los caracteres de nueva línea también:

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

Uso Properties.loadFromXML(InputStream). No hay necesidad de bibliotecas externas.

Mejor que un código desordenado (ya que la mantenibilidad y el diseño son su preocupación), es preferible no utilizar cadenas largas.
Comience por leer las propiedades XML:

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


entonces usted puede utilizar su cadena de varias de manera más fácil de mantener ...

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


MultiLine.xml` se encuentra en la misma carpeta 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 .: Puede utilizar <![CDATA[" ... "]]> para la cadena XML similar.

Una solución independiente bastante eficiente y la plataforma sería el uso de la propiedad del sistema de separadores de línea y la clase StringBuilder para construir cadenas:

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

JDK / 12 acceso temprano acumulación # 12 , uno puede ahora utilizar líneas múltiples en Java como sigue:

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

y esto resulta en la salida siguiente:

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

Definir mi cadena en un archivo de propiedades?

cadenas de varias líneas no están permitidos en los archivos de propiedades. Se puede usar \ n en los archivos de propiedades, pero no creo que es mucho de una solución en su caso.

Una buena opción.

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

    }

Sé que esto es una cuestión de edad, sin embargo, para los desarrolladores intersted Multi literales de la línea que va a estar en # Java12

http://mail.openjdk.java .NET / pipermail / ámbar-dev / 2018-julio / 003254.html

se sugiere emplear una utilidad como sugiere ThomasP, y luego enlazar que en su proceso de construcción. Un archivo externo todavía está presente para contener el texto, pero el archivo no se lee en tiempo de ejecución. El flujo de trabajo es entonces:

  1. Construir una utilidad 'archivo de texto con el código java' y comprobar en el control de versiones
  2. En cada generación, ejecute el programa de utilidad en el archivo de recursos para crear una fuente de Java revisada
  3. La fuente de Java contiene un encabezado como class TextBlock {... seguido de una cadena estática que es auto-generada a partir del archivo de recursos
  4. Construir el archivo Java generado con el resto de su código

Cuando se utiliza una larga serie de +, sólo se crea un StringBuilder, a menos que la cadena se determina en tiempo de compilación en cuyo caso no se utiliza ningún StringBuilder!

El único StringBuilder tiempo es más eficiente es cuando se utilizan varias instrucciones para construir la cadena.

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:. Sólo se crea 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
  

Para aclarar aún más mi pregunta, no estoy preocupado por el rendimiento en absoluto. Estoy preocupado por los problemas de mantenimiento y diseño.

Que sea lo más claro y simple como sea posible.

Un pequeño truco. El uso de este inyecto JavaScript en una página HTML creado dinámicamente

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

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top