¿Por qué no hay String.Empty en Java?

260

Entiendo que cada vez que escribo el literal de cadena "", se hace referencia al mismo objeto de cadena en el grupo de cadenas.

Pero, ¿por qué la API de cadena no incluye a public static final String Empty = "";, por lo que podría usar referencias String.Empty?

Ahorraría tiempo de compilación, como mínimo, ya que el compilador sabría hacer referencia a la Cadena existente y no tendría que verificar si ya se ha creado para su reutilización, ¿verdad? Y personalmente creo que la proliferación de literales de cadena, especialmente los pequeños, en muchos casos es un "olor a código".

Entonces, ¿hubo una Gran razón de diseño detrás de String.Empty, o los creadores del lenguaje simplemente no compartieron mis puntos de vista?

Tom Tresansky
fuente
55
Aidanc: Creo que quiere decir situaciones en las que la materia como outputBlah = "", y probablemente prefiere something == String.Emptymás something.Length > 0, así (se salta un cheque nulo.)
Skurmedel
2
@Aidanc: estaba buscando un "miembro vacío" como Collections.EMPTY_SET , no una función para verificar el "vacío" de la cadena.
Tim Stone
2
@Aidanc: Lo que inspiró esto es en realidad 'TextBox.setText ("");'.
Tom Tresansky
3
Hay una String.isEmpty()función ... ¿por qué quieres String.EMPTY?
Buhake Sindi
8
String.isEmpty()no devuelve una cadena vacía.
Steve Kuo

Respuestas:

191

String.EMPTYtiene 12 caracteres y ""dos, y ambos estarían haciendo referencia exactamente a la misma instancia en la memoria en tiempo de ejecución. No estoy completamente seguro de por String.EMPTYqué ahorraría tiempo de compilación, de hecho creo que sería lo último.

Especialmente teniendo en cuenta que los Strings son inmutables, no es como si primero pudieras obtener un String vacío y realizar algunas operaciones en él, lo mejor es usar un StringBuilder(o StringBuffersi quieres ser seguro para subprocesos) y convertirlo en un String.

Actualización de
su comentario a la pregunta:

Lo que inspiró esto es en realidad TextBox.setText("");

Creo que sería totalmente legítimo proporcionar una constante en su clase apropiada:

private static final String EMPTY_STRING = "";

Y luego referencialo como en tu código como

TextBox.setText(EMPTY_STRING);

De esta manera, al menos, es explícito que desea una Cadena vacía, en lugar de haber olvidado completar la Cadena en su IDE o algo similar.

Noel M
fuente
14
Todavía haré +1 en ti, pero me siento sucio porque mencionaste StringBuildersin hablar de cómo nueve de cada diez veces es totalmente inapropiado usarlo en StringBuilderlugar de concatenación.
Randolpho
85
Tiendo a preferir string.empty, principalmente porque es más explícito. Además, hay situaciones de frecuencia en las que puede ser más difícil diferenciar visualmente "" y cosas como "'". Al final, como otros han notado, es solo una de esas cosas de estilo sin sentido que nos dan forraje para discutir cuando estamos aburridos con el trabajo real. =)
JohnFx
@Nodel M: Con respecto al tiempo de compilación, supongo que si hay 2 literales de cadena definidos en 2 archivos de origen diferentes con el mismo valor de cadena, cuando el compilador llega al segundo, debe hacer algún tipo de comprobación para descubrir " oye, ya sé sobre esta cadena desde aquí ". Es cierto que no soy un experto en el compilador de Java, pero ¿cómo podría NO ser así? Y creo que omitir esa verificación daría lugar a una mejora minúscula en los tiempos de compilación.
Tom Tresansky
@Tom: creo que el internamiento de String se realiza en tiempo de ejecución, no en tiempo de compilación, por lo que, en realidad, si tiene la cadena vacía como una constante en otro archivo, el compilador debe hacer referencia a esa clase para resolver el literal de String.
Noel M
1
@Randolpho Al usar la concatenación de cadenas, en realidad estás usando un StringBuilder debajo del capó.
whiskeysierra
133

Utilizar org.apache.commons.lang.StringUtils.EMPTY

jade
fuente
30
Se ve mucho mejor y más fácil de leer que un "" vacío. Espero que no sea solo yo.
Lakatos Gyula
2
@LakatosGyula - Creo que podría ser (solo tú). Los programadores competentes de Java no tienen problemas para leer ""... y la mayoría probablemente se opondría en voz alta sobre el uso, EMPTYexcepto en situaciones específicas donde EMPTYtiene un significado específico de dominio. (Y en tales casos, probablemente haya un nombre más apropiado.)
Stephen C
14
@LakatosGyula No eres solo tú. Pasé de Java al desarrollo .NET, y String.Empty fue una característica que me complació encontrar en el marco. Me gusta su naturaleza explícita sobre un conjunto vacío de citas.
yohohoho
64
@StephenC Cuando veo un "" vacío, lo primero que me viene a la mente es que es un error, alguien no ha terminado la función, etc. Con String.EMPTY sé exactamente que el desarrollador tenía la intención de devolver una cadena vacía.
Lakatos Gyula
1
También es útil para todos aquellos momentos en que la frase dice "usa una constante con nombre en lugar de bla, bla, bla". Todo programador sabe que "" no es mágico, pero es mejor no tener que explicárselo al cliente.
LizH
28

Si desea comparar con una cadena vacía sin preocuparse por los valores nulos, puede hacer lo siguiente.

if ("".equals(text))

En última instancia, debe hacer lo que cree que es más claro. La mayoría de los programadores asumen que "" significa cadena vacía, no una cadena en la que alguien olvidó poner algo.

Si cree que hay una ventaja de rendimiento, debe probarla. Si no cree que valga la pena probarlo usted mismo, es una buena indicación de que realmente no vale la pena.

Parece que intentas resolver un problema que se resolvió cuando el lenguaje fue diseñado hace más de 15 años.

Peter Lawrey
fuente
1
Llego bastante tarde a la fiesta pero, dado que las cadenas de Java son inmutables, creo que todas las cadenas vacías dentro de una JVM son solo referencias diferentes al mismo objeto de cadena. Entonces, simplemente lo siguiente también es correcto: if ("" == text)
Ajoy Bhatia
12
@AjoyBhatia El problema es que puedes crear nuevas cadenas vacías. if ("" == new String())Es falso. Una mejor pruebaif(text.isEmpty())
Peter Lawrey, el
1
@AjoyBhatia: solo si las cadenas están internadas. stackoverflow.com/questions/10578984/what-is-string-interning
Davor
9

Si realmente desea una constante String.EMPTY, puede crear una clase final estática de utilidad denominada "Constantes" (por ejemplo) en su proyecto. Esta clase mantendrá sus constantes, incluida la cadena vacía ...

En la misma idea, puede crear ZERO, ONE int constantes ... que no existen en la clase Integer, pero como comenté, sería difícil escribir y leer:

for(int i=Constants.ZERO; ...) {
    if(myArray.length > Constants.ONE) {
        System.out.println("More than one element");
    }
}

Etc.

Benoit Courtine
fuente
8

Apache StringUtils también soluciona este problema.

Fallos de las otras opciones:

  • isEmpty () - no es nulo seguro. Si la cadena es nula, arroja un NPE
  • length () == 0 - nuevamente no es nulo seguro. Tampoco tiene en cuenta las cadenas de espacios en blanco.
  • Comparación con constante VACÍO: puede no ser nulo seguro. Problema de espacios en blanco

Granted StringUtils es otra biblioteca para arrastrar, pero funciona muy bien y ahorra un montón de tiempo y comprobaciones sin problemas para detectar nulos o manejar NPE con gracia.

Freiheit
fuente
3
entonces ... parece que la única opción segura es la horrible condición de Yoda "".equals(s):?
Lie Ryan
8

No solo diga "el conjunto de cadenas de memoria se reutiliza en forma literal, caso cerrado". Lo que hacen los compiladores bajo el capó no es el punto aquí. La pregunta es razonable, especialmente dada la cantidad de votos positivos que recibió.

Se trata de la simetría , sin ella las API son más difíciles de usar para los humanos. Los primeros SDK de Java ignoraron notoriamente la regla y ahora es demasiado tarde. Aquí hay algunos ejemplos sobre mi cabeza, siéntase libre de incluir su ejemplo "favorito":

  • BigDecimal.ZERO, pero no AbstractCollection.EMPTY, String.EMPTY
  • Array.length pero List.size ()
  • List.add (), Set.add () pero Map.put (), ByteBuffer.put () y no olvidemos StringBuilder.append (), Stack.push ()
Slawomir
fuente
Incluso si nombró la longitud del parámetro Lista (), aún necesita el paréntesis ya que es un método. Array.length es una variable final pública, que solo funciona porque las matrices son inmutables. Entonces todavía tendría Array.length y List.length (). Yo diría que es más confuso y propenso al error. En cuanto a .append () y .push (), aunque realizan tareas similares, creo que lo nombraron adecuadamente. Agregar la cadena es exactamente lo que está haciendo, pero no "agrega" una pila, empuja y resalta los valores. Y StringBuilder.push () implicaría StringBuilder.pop (), lo cual no es posible.
Craig Parton el
Viniendo de plantillas / genéricos, las interfaces consistentes también ayudan con los algoritmos. Si un algoritmo necesita una longitud de una colección, la longitud (T) o T.length () es todo lo que nos importa. Del mismo modo, la adición al final de una pila, lista o cadena podría realizarse mediante un add () o append () universal. Usted mencionó que la matriz en Java es de tipo inmutable / incorporado con una propiedad de longitud expuesta. Eso está bien, no significa que el compilador no pueda manejar o generar código para la longitud (T) o T.length (). Kotlin genera una serie de métodos intrínsecos para varios casos.
Slawomir el
Pero un método consistentemente llamado length () solo nos permite verificar la longitud. ¿Qué tan útil es eso? Si su objetivo es abstraer Listas y Arreglos para hacerlos utilizables de alguna manera a través de una interfaz, también necesita una forma consistente de leer o escribir datos. Entonces ahora necesita generar los métodos get (), set () y add (). Básicamente, está creando una vista de lista menos funcional de la matriz. Dado que Arrays.asList () está disponible, es fácil de usar y es liviano, ¿por qué reinventar la rueda? Las matrices, listas, StringBuilders y Stacks tienen un propósito específico. Parece mejor diseñar su interfaz para usar el mejor ajuste.
Craig Parton el
5

Todos esos ""literales son el mismo objeto. ¿Por qué hacer toda esa complejidad extra? Es más largo de escribir y menos claro (el costo para el compilador es mínimo). Dado que las cadenas de Java son objetos inmutables, nunca hay necesidad de distinguir entre ellas, excepto posiblemente como una cuestión de eficiencia, pero con el literal de cadena vacío no es gran cosa.

Si realmente quieres una EmptyStringconstante, hazlo tú mismo. Pero todo lo que hará es alentar un código aún más detallado; no habrá nunca más ningún beneficio al hacerlo.

Compañeros de Donal
fuente
27
x = String.Emptytransmite intención mejor que x = "". Esto último podría ser una omisión accidental. Decir que nunca hay ningún beneficio es incorrecto.
Jeffrey L Whitledge
@ Jeffrey: No creo que esté particularmente de acuerdo. Es una de estas cosas donde no hay una regla dura y rápida, supongo.
Donal Fellows
Sí, es importante señalar que el compilador de Java comprueba si ya existen literales de cadena antes de crear una nueva instancia en el grupo de cadenas.
rds
1
@Jeffrey: sabiendo que esta es una discusión muy antigua y subjetiva. x = String.Emptytransmite intención, cierto. Pero supongamos que el lenguaje proporciona una constante String.Empty, cuando te encuentras x = ""todavía sabes exactamente tanto sobre la intención como si no hubiera una constante. Debería garantizar que todos los lugares del código Java del mundo donde se encontraba una cadena vacía no se utilizan ""para obtener la ganancia de información que usted menciona. Irónicamente, C # usa una constante y alienta su uso, por lo que, como dije, sé que es una discusión muy opinión.
chiccodoro
@chiccodoro - Sí, eso es cierto. Es por eso que el literal de cadena vacía ""debería ser ilegal, para descartar accidentes. ¡Estoy bromenando!
Jeffrey L Whitledge
4

Para agregar a lo que dijo Noel M, puede ver esta pregunta, y esta respuesta muestra que la constante se reutiliza.

http://forums.java.net/jive/message.jspa?messageID=17122

Las cadenas constantes siempre están "internados", por lo que realmente no hay necesidad de tal constante.

String s=""; String t=""; boolean b=s==t; // true
James Black
fuente
1
El enlace está muerto.
dieter
3

Entiendo que cada vez que escribo el literal de cadena "", se hace referencia al mismo objeto de cadena en el grupo de cadenas.
No hay tal garantía hecha. Y no puede confiar en él en su aplicación, depende completamente de jvm decidir.

¿O los creadores del lenguaje simplemente no compartieron mis puntos de vista?
Sí. Para mí, parece algo de muy baja prioridad.

Nikita Rybak
fuente
66
No hay tal garantía hecha ... Bueno, el JLS afirma que ese debería ser el caso.
Tim Stone
@Tim No a menos que hagas una llamada 'interna'. Es fácil construir dos cadenas grandes iguales mediante programación y verificar.
Nikita Rybak
@Tim Por ejemplo, repita a + = "a"; 100 veces, haz lo mismo con by check.
Nikita Rybak
55
Tienes razón, pero lo que has descrito no es un literal de cadena, ni una expresión cuyo resultado se pueda garantizar en tiempo de compilación (como String username = "Bob" + " " + "Smith";). Las cadenas creadas mediante programación no tienen garantías de ser internados, a menos que llame explícitamente intern()como ha indicado. Sin ""embargo, el escenario del OP describe el uso del literal de cadena en blanco en todo el código, que es un caso en el que ocurriría una internación automática.
Tim Stone
@Tim String a = ""; for(int i = 0; i < 100; i++) {a += "a";} String b = ""; for(int i = 0; i < 100; i++) {b += "b";} a.intern(); b.intern();Ahora el ay bapunta a la misma ubicación de memoria en PermGen. Ver este artículo
1ac0
1

Respuesta tardía, pero creo que agrega algo nuevo a este tema.

Ninguna de las respuestas anteriores ha respondido a la pregunta original. Algunos han intentado justificar la falta de una constante, mientras que otros han mostrado formas en que podemos lidiar con la falta de la constante. Pero nadie ha brindado una justificación convincente para el beneficio de la constante, por lo que su falta aún no se explica adecuadamente.

Una constante sería útil porque evitaría que ciertos errores de código pasen desapercibidos.

Digamos que tiene una base de código grande con cientos de referencias a "". Alguien modifica uno de estos mientras se desplaza por el código y lo cambia a "". Tal cambio tendría una alta probabilidad de pasar desapercibido en la producción, en cuyo punto podría causar algún problema cuya fuente será difícil de detectar.

OTOH, una constante de biblioteca llamada EMPTY, si está sujeta al mismo error, generaría un error de compilación para algo como EM PTY.

Definir tu propia constante es aún mejor. Alguien aún podría alterar su inicialización por error, pero debido a su amplio uso, el impacto de dicho error sería mucho más difícil pasar desapercibido que un error en un solo caso de uso.

Este es uno de los beneficios generales que obtiene al usar constantes en lugar de valores literales. Las personas generalmente reconocen que el uso de una constante para un valor utilizado en docenas de lugares le permite actualizar fácilmente ese valor en un solo lugar. Lo que se reconoce con menos frecuencia es que esto también evita que ese valor se modifique accidentalmente, porque tal cambio se vería en todas partes. Entonces, sí, "" es más corto que VACÍO, pero VACÍO es más seguro de usar que "".

Entonces, volviendo a la pregunta original, solo podemos especular que los diseñadores de lenguaje probablemente no estaban al tanto de este beneficio de proporcionar constantes para valores literales que se usan con frecuencia. Con suerte, algún día veremos constantes de cadena agregadas en Java.

Laurentiu Cristofor
fuente
-16

Para aquellos que reclaman ""y String.Emptyson intercambiables o eso ""es mejor, estás muy equivocado.

Cada vez que haces algo como myVariable = ""; Estás creando una instancia de un objeto. Si el objeto String de Java tuviera una constante pública VACÍA, solo habría 1 instancia del objeto ""

P.ej: -

String.EMPTY = ""; //Simply demonstrating. I realize this is invalid syntax

myVar0 = String.EMPTY;
myVar1 = String.EMPTY;
myVar2 = String.EMPTY;
myVar3 = String.EMPTY;
myVar4 = String.EMPTY;
myVar5 = String.EMPTY;
myVar6 = String.EMPTY;
myVar7 = String.EMPTY;
myVar8 = String.EMPTY;
myVar9 = String.EMPTY;

10 (11 incluyendo String.EMPTY) Punteros a 1 objeto

O: -

myVar0 = "";
myVar1 = "";
myVar2 = "";
myVar3 = "";
myVar4 = "";
myVar5 = "";
myVar6 = "";
myVar7 = "";
myVar8 = "";
myVar9 = "";

10 punteros a 10 objetos

Esto es ineficiente y, a lo largo de una aplicación grande, puede ser significativo.

Quizás el compilador de Java o el tiempo de ejecución sea lo suficientemente eficiente como para apuntar automáticamente todas las instancias de "" a la misma instancia, pero podría no serlo y requiere un procesamiento adicional para tomar esa determinación.

Cabina de antony
fuente
9
Incorrecto, de acuerdo con stackoverflow.com/questions/1881922/… , la cadena "" se reutilizará del conjunto de cadenas.
RealHowTo
1
Dije que podría reutilizar el mismo objeto y, de ser así, aún es menos eficiente, porque necesita encontrar ese objeto (en el conjunto de cadenas), entonces, ¿cómo me equivoco? En cualquier caso, hay varias razones por las que String.Empty es superior, incluida la prevención de errores como myVar = ""; y legibilidad, así como la mejora del rendimiento que ya dije. Es una buena práctica usar constantes en lugar de crear literales de cadena, si no por otra razón; Es más fácil mantener el código.
Antony Booth
1
Dudo que su argumento de rendimiento sea válido porque JLS dice que una constante se tratará como literal en tiempo de compilación ( docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10. 5 ) La legibilidad es un mejor argumento.
RealHowTo
3
@AntonySmith: supongo que debes estudiar Java un poco más o tal vez ya sepas tu error. Las cadenas de Java son inmutables y están en un grupo. Por lo tanto, solo hay un objeto de cadena para "" en una JVM, sin importar cuántas veces se encuentre en el código. Puede verificar si una cadena está vacía haciendoif (text == "")
Ajoy Bhatia
2
Incorrecto. Este comentario debe ser eliminado.
Elad Tabak