codigo - Cadena multilínea de Java
textarea java netbeans (30)
Viniendo de Perl, estoy seguro de que me falta el "documento aquí" para crear una cadena multilínea en el código fuente
$string = <<"EOF" # create a three-line string
text
text
text
EOF
En Java, tengo que tener incómodas citas y signos más en cada línea, ya que concatené mi cadena multilínea desde cero.
¿Cuáles son algunas de las mejores alternativas? ¿Definir mi cadena en un archivo de propiedades?
Edición : dos respuestas dicen que StringBuilder.append () es preferible a la notación positiva. ¿Alguien podría explicar por qué piensan eso? No me parece más preferible en absoluto. Estoy buscando una manera de evitar el hecho de que las cadenas multilínea no son una construcción de lenguaje de primera clase, lo que significa que definitivamente no quiero reemplazar una construcción de lenguaje de primera clase (concatenación de cadenas con más) con llamadas a métodos.
Edit : para aclarar más mi pregunta, no me preocupa el rendimiento en absoluto. Me preocupa la mantenibilidad y los problemas de diseño.
¿Definir mi cadena en un archivo de propiedades?
No se permiten cadenas multilínea en los archivos de propiedades. Puede usar / n en los archivos de propiedades, pero no creo que sea una solución para su caso.
String.join
Java 8 agregó un nuevo método estático a java.lang.String
que ofrece una alternativa ligeramente mejor:
String.join( CharSequence delimiter , CharSequence... elements )
Usándolo:
String s = String.join(
System.getProperty("line.separator"),
"First line.",
"Second line.",
"The rest.",
"And the last!"
);
Cuando se usa una larga serie de +, solo se crea un StringBuilder, a menos que el String se determine en el momento de la compilación, en cuyo caso no se usa StringBuilder.
La única vez que StringBuilder es más eficiente es cuando se usan varias declaraciones para construir el String.
String a = "a/n";
String b = "b/n";
String c = "c/n";
String d = "d/n";
String abcd = a + b + c + d;
System.out.println(abcd);
String abcd2 = "a/n" +
"b/n" +
"c/n" +
"d/n";
System.out.println(abcd2);
Nota: 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 más mi pregunta, no me preocupa el rendimiento en absoluto. Me preocupa la mantenibilidad y los problemas de diseño.
Hazlo tan claro y simple como puedas.
Dado que Java no (todavía) soporta cadenas multilínea nativas, la única manera por ahora es hackearlo usando una de las técnicas mencionadas anteriormente. Construí el siguiente script de 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 '')''
Ponga eso en un archivo llamado javastringify.py y su cadena en un archivo mystring.txt y ejecútelo de la siguiente manera:
cat mystring.txt | python javastringify.py
Luego puedes copiar la salida y pegarla en tu editor.
Modifique esto según sea necesario para manejar casos especiales, pero esto funciona para mis necesidades. ¡Espero que esto ayude!
El último modelo JAVA tiene optimizaciones para + con cadenas constantes, emplea un StringBuffer detrás de escena, por lo que no desea saturar su código con él.
Apunta a una supervisión de JAVA, que no se parece a ANSI C en la concatenación automática de cadenas entre comillas dobles con solo espacios en blanco entre ellas, por ejemplo:
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" ;
Me encantaría tener una constante de matriz de caracteres multilínea donde se respeten los saltos de línea incrustados, por lo que puedo presentar el bloque sin ningún desorden, por ejemplo:
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
" ;
Para conseguir esto, uno necesita vencer a los dioses JAVA.
En Eclipse, si activa la opción "Escape de texto al pegar en una cadena literal" (en Preferencias> Java> Editor> Escritura) y pega una cadena con múltiples líneas entre comillas, agregará automáticamente "
y /n" +
para todos. tus lineas
String str = "paste your text here";
En el IDE de IntelliJ solo necesitas escribir:
""
Luego coloca el cursor dentro de las comillas y pega la cadena. El IDE lo expandirá en múltiples líneas concatenadas.
En realidad, la siguiente es la implementación más limpia 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;
Entonces, el resultado final es que la variable html contiene la cadena de varias líneas. Sin comillas, sin ventajas, sin comas, solo cadena pura.
Esta solución está disponible en la siguiente URL ... http://www.adrianwalker.org/2011/12/java-multiline-string.html
¡Espero que ayude!
Este es un hilo antiguo, pero una nueva solución bastante elegante (con un solo inconveniente) es utilizar una anotación personalizada.
Compruebe: http://www.adrianwalker.org/2011/12/java-multiline-string.html
Editar: La URL anterior parece estar rota. Un proyecto inspirado en ese trabajo está alojado en 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);
}
}
El inconveniente es que tiene que activar el procesador de anotación correspondiente (provisto).
Y probablemente tengas que configurar Eclipse para que no reformatee automáticamente tus comentarios de Javadoc.
Es posible que esto resulte extraño (los comentarios de Javadoc no están diseñados para incrustar nada más que comentarios), pero como esta falta de cadena multilínea en Java es realmente molesta al final, me parece que esta es la solución peor.
Esto es algo que nunca debes usar sin pensar en lo que está haciendo. Pero para los scripts únicos, lo he usado 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();
}
Lamentablemente, Java no tiene literales de cadena multilínea. Tienes que concatenar literales de cadena (usando los dos enfoques más comunes para esto) o leer StringBuilder o leer la cadena desde un archivo separado.
Para los literales de cadena multilínea grandes, me inclinaría a usar un archivo separado y leerlo usando getResourceAsStream()
(un método de la clase Class
). Esto facilita la búsqueda del archivo, ya que no tiene que preocuparse por el directorio actual en lugar de dónde se instaló su código. También facilita el empaquetado, ya que realmente puede almacenar el archivo en su archivo jar.
Supongamos que estás en una clase llamada Foo. Solo haz 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 método estándar de "leer todo el texto de este lector en una cadena". Aunque es bastante fácil escribir:
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();
}
Las ventajas se convierten en StringBuilder.append, excepto cuando ambas cadenas son constantes, de modo que el compilador puede combinarlas en el momento de la compilación. Al menos, así es en el compilador de Sun, y yo sospecharía que la mayoría, si no todos los demás compiladores, harían lo mismo.
Asi 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 otra parte:
String c="Hello"+"Goodbye";
es lo mismo que:
String c="HelloGoodbye";
Es decir, no hay ninguna penalización por dividir sus cadenas literales en varias líneas con signos más para facilitar la lectura.
Otra opción puede ser almacenar cadenas largas en un archivo externo y leer el archivo en una cadena.
Parece que quieres hacer un literal multilínea, que no existe en Java.
Tu mejor alternativa será cadenas que estén +
juntas. Algunas otras opciones que la gente ha mencionado (StringBuilder, String.format, String.join) solo serían preferibles si comenzara con una matriz de cadenas.
Considera 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 la nueva línea para su sistema en particular, necesita usar System.getProperty("line.separator")
, o puede usar %n
en String.format
.
Otra opción es colocar el recurso en un archivo de texto y simplemente leer el contenido de ese archivo. Esto sería preferible para cadenas muy grandes para evitar innecesariamente la hinchazón de sus archivos de clase.
Puede usar scala-code, que es compatible con Java, y permite cadenas de varias líneas incluidas con "" ":
package foobar
object SWrap {
def bar = """John said: "This is
a test
a bloody test,
my dear." and closed the door."""
}
(note las comillas dentro de la cadena) y desde java:
String s2 = foobar.SWrap.bar ();
Si esto es más cómodo ...?
Otro enfoque, si suele manejar texto largo, que debe colocarse en su código fuente, podría ser un script, que toma el texto de un archivo externo y lo envuelve como una cadena multilínea-java como esta:
sed ''1s/^/String s = /"/;2,$s/^//t+ "/;2,$s/$/"/'' file > file.java
para que puedas cortarlo y pegarlo fácilmente en tu fuente.
Puedes concatenar tus apéndices 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.toStirng();
}
De cualquier manera, prefiera StringBuilder
a la notación positiva.
Si define sus cadenas en un archivo de propiedades, se verá mucho peor. IIRC, se verá como
string:text/u000atext/u000atext/u000a
En general, es una idea razonable no insertar cadenas grandes en la fuente. Es posible que desee cargarlos como recursos, quizás en XML o en un formato de texto legible. Los archivos de texto pueden leerse en tiempo de ejecución o compilarse en la fuente Java. Si terminas colocándolos en la fuente, sugiero colocar el +
en la parte delantera y omitir nuevas líneas innecesarias:
final String text = ""
+"text "
+"text "
+"text"
;
Si tiene nuevas líneas, es posible que desee algunos métodos de unión o formato:
final String text = join("/r/n"
,"text"
,"text"
,"text"
);
Si te gusta la guayaba de Google tanto como a mí, puede dar una representación bastante clara y una forma agradable y fácil de no codificar los caracteres de tu nueva línea también:
String out = Joiner.on(newline).join(ImmutableList.of(
"line1",
"line2",
"line3"));
Stephen Colebourne ha creado una proposal para agregar cadenas multilínea en Java 7.
Además, Groovy ya tiene soporte para cadenas multilínea .
Un pequeño truco. Usando esto, inyecto javascritp en una página HTML creada 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();
}
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();
Además, el hecho de que java.io.BufferedWriter
tiene un método newLine()
no se menciona.
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);
}
}
Una solución bastante eficiente e independiente de la plataforma sería utilizar la propiedad del sistema para separadores de línea y la clase StringBuilder para crear 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();
Ver Java Stringfier . Convierte tu texto en un bloque java StringBuilder que se escapa si es necesario.
openjdk.java.net/jeps/326 implementarán cadenas de varias líneas, por lo que podrá escribir algo como:
String s = `
text
text
text
`;
Se planea como una vista previa de características en JDK 12 .
Sé que esta es una pregunta antigua, sin embargo, para los desarrolladores interesados, los literales multilínea estarán en # Java12
http://mail.openjdk.java.net/pipermail/amber-dev/2018-July/003254.html
Sugiero usar una utilidad como lo sugiere ThomasP, y luego vincularlo a su proceso de compilació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:
- Cree una utilidad ''archivo de texto a código java'' y verifique en el control de versiones
- En cada compilación, ejecute la utilidad contra el archivo de recursos para crear una fuente java revisada
- La fuente Java contiene un encabezado como
class TextBlock {...
seguido de una cadena estática que se genera automáticamente desde el archivo de recursos - Construye el archivo java generado con el resto de tu código
Utilizar Properties.loadFromXML(InputStream)
. No hay necesidad de libs externos.
Mejor que un código desordenado (ya que su mantenimiento y diseño son su preocupación), es preferible no usar cadenas largas.
Comience por leer las propiedades xml:
InputStream fileIS = YourClass.class.getResourceAsStream("MultiLine.xml");
Properties prop = new Properies();
prop.loadFromXML(fileIS);
entonces puedes usar tu cadena multilínea de una manera más mantenible ...
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 .: Puedes usar <![CDATA["
... "]]>
para una cadena similar a xml.
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");
String newline = System.getProperty ("line.separator");
string1 + newline + string2 + newline + string3
Pero, la mejor alternativa es usar String.format
String multilineString = String.format("%s/n%s/n%s/n",line1,line2,line3);