2009-02-10 25 views
30

Tengo una pregunta sobre la comparación de una cadena con la cadena vacía en Java. ¿Hay alguna diferencia si comparo una cadena con la cadena vacía con == o equals? Por ejemplo:Comparando una cadena con la cadena vacía (Java)

String s1 = "hi"; 

if (s1 == "") 

o

if (s1.equals("")) 

Yo sé que uno debe comparar cadenas (y objetos en general) con equals, y no ==, pero me pregunto si tiene importancia para la cadena vacía.

+0

¿No está comparando la longitud mejor manera? Creo que la comparación de longitud está más optimizada que la comparación de cadenas – Ravisha

+0

@Ravisha Internally, ['String.java''s] (http://www.docjar.com/html/api/java/lang/String.java.html)' El método equals' tiene varias optimizaciones: ** 1: ** Referencia '==' comparación, ** 2: ** 'instancia de cadena de verificación antes del casting, y ** 3: ** longitud del valor de comparación antes de finalmente comparar las cadenas charachter por personaje Entonces, para responder a su pregunta, sí, la comparación de longitud es eficiente, pero su código debe confiar en String.equals y no reinventar ninguna de sus ruedas. –

+0

@Patrick M. Si la intención aquí es verificar la cadena vacía, prefiero comparar la longitud. En lugar de comparación. – Ravisha

Respuesta

26

Va a depender de si la cadena es literal o no. Si crea la cadena con

new String("") 

entonces nunca coincidirá con "" con el operador de igualdad, como se muestra a continuación:

String one = ""; 
    String two = new String(""); 
    System.out.println("one == \"\": " + (one == "")); 
    System.out.println("one.equals(\"\"): " + one.equals("")); 
    System.out.println("two == \"\": " + (two == "")); 
    System.out.println("two.equals(\"\"): " + two.equals("")); 

-

one == "": true 
one.equals(""): true 
two == "": false 
two.equals(""): true 

Básicamente, usted quiere siempre use igual()

+0

Puede valer la pena mostrar un ejemplo de código de iguales() también. – Kezzer

6

Una cadena, es una cadena, es una cadena, ya sea la cadena vacía o no. Use equals().

66
s1 == "" 

no es fiable, ya que pone a prueba la igualdad de referencia se opone la igualdad (y la cadena no es estrictamente canónica).

s1.equals("") 

es mejor, pero puede sufrir excepciones de puntero nulo. Mejor aún es:

"".equals(s1) 

Sin excepciones de punteros nulos.

EDITAR: Bien, se preguntó sobre el punto canonical form. Este artículo lo define como:

Supongamos que tenemos algún conjunto S de objetos, con una relación de equivalencia. Una forma canónica se da al designar algunos objetos de S para que sean "en forma canónica ", de modo que cada objeto bajo consideración es equivalente exactamente a un objeto en forma canónica.

Para darle un ejemplo práctico: tome el conjunto de números racionales (o "fracciones" como se llaman comúnmente). Un número racional consiste en un numerador y un denomoinator (divisor), ambos son enteros. Estos números racionales son equivalentes:

3/2, 6/4, 24/16

nubmers racionales son típicamente escritos de tal manera que el mcd (máximo común divisor) es 1. Así que todos ellos se simplificará a 3/2. 3/2 se puede ver como forma canónica de este conjunto de números racionales.

Entonces, ¿qué significa en programación cuando se usa el término "forma canónica"? Puede significar un par de cosas. Tomemos por ejemplo esta clase imaginaria:

public class MyInt { 
    private final int number; 

    public MyInt(int number) { this.number = number; } 
    public int hashCode() { return number; } 
} 

El código hash de la clase myInt es una forma canónica de esa clase ya que para el conjunto de todas las instancias de myInt, puede tomar cualquiera de los dos m1 elementos y m2 y lo harán obedezca la siguiente relación:

m1.equals(m2) == (m1.hashCode() == m2.hashCode()) 

Esa relación es la esencia de la forma canónica. Una forma más común de esta surge es cuando se utiliza métodos de fábrica en clases tales como:

public class MyClass { 
    private MyClass() { } 

    public MyClass getInstance(...) { ... } 
} 

instancias no se pueden crear instancias directamente porque el constructor es privado. Este es solo un método de fábrica. Lo que un método de fábrica le permite hacer es cosas como:

  • Devolver siempre la misma instancia (singleton abstraído);
  • Simplemente crea una nueva intsance con cada llamada;
  • Devuelve objetos en forma canónica (más sobre esto en un segundo); o
  • lo que quieras.

Básicamente, el método de fábrica abstrae la creación de objetos y, personalmente, creo que sería una característica de lenguaje interesante forzar a todos los constructores a ser privados para imponer el uso de este patrón, pero estoy divagando.

Lo que puede hacer con este método de fábrica es caché de las instancias que se crea tal que para cualesquiera dos casos S1 y S2 obedecen a la siguiente prueba:

(s1 == s2) == s1.equals(s2) 

Así que cuando digo cadena no es estrictamente canónica que significa que:

String s1 = "blah"; 
String s2 = "blah"; 
System.out.println(s1 == s2); // true 

Pero, como otros han poitned OUT puede cambiar esto usando:

String s3 = new String("blah"); 

y posiblemente:

String s4 = String.intern("blah"); 

Así que no se puede confiar en la igualdad de referencia completamente por lo que no debe confiar en ella en absoluto.

Como advertencia al patrón anterior, debo señalar que controlar la creación de objetos con constructores privados y métodos de fábrica no garantiza que la igualdad de referencia signifique igualdad de objetos debido a la serialización. La serialización evita el mecanismo normal de creación de objetos. Josh Bloch cubre este tema en Effective Java (originalmente en la primera edición cuando habló sobre el patrón de ensafe tipo seguro que más tarde se convirtió en una característica del lenguaje en Java 5) y puede evitarlo al sobrecargar el método (privado) readResolve(). Pero es complicado. Los cargadores de clases también afectarán el problema.

De todos modos, eso es forma canónica.

+1

+1 para una gran explicación. Pero es posible que desee explicar qué significa "canónico" en este contexto: que la JVM contiene una tabla de cadenas creadas, por lo que no necesita crear la misma cadena repetidamente. Uno de los pocos lugares en Java tiene una clara ventaja de rendimiento sobre C y C++. – rtperson

+0

Para C/C++, GCC al menos tiene una opción de tiempo de compilación para reutilizar constantes de cadena. Es lo suficientemente inteligente como para admitir subcadenas cuando sea posible, también. Sin embargo, esto no ocurre en tiempo de ejecución (a menos que tenga una biblioteca que hace esto, por ejemplo, utilizando el uso compartido implícito como Qt). – strager

+1

+1 for "" .equals (str) ... no puedo creer que esto nunca se me haya ocurrido. – Tom

9
"".equals(s) 

parece ser la mejor opción, pero también hay Stringutils.isEmpty(s) contenida en la biblioteca Apache Commons Lang

+6

Interesante, una llamada a la biblioteca que es más larga y oscura que el código que reemplaza. ;) –

+0

Si bien no agregaría Commons-lang para esto si no lo estuviese utilizando para otra cosa, es probable que lo * use *. La versión que evita el puntero nulo de la declaración siempre me ha dado colmenas y odio el cheque de forma nula también, así que prefiero la versión de StringUtils. –

+1

si bien es más larga, no es más oscuro utilizar una llamada de biblioteca como StringUtil.isNullOrEmpty (someString); , y la razón es que tener un nombre allí lo hace mucho más legible. el golpe de rendimiento es insignificante, por lo que es una victoria. – Chii

10

Es un poco hacia los lados de su pregunta original, pero siempre hay

if(s1.length() == 0) 

I cree que esto es equivalente al método isEmpty() de 1.6.

+1

Este tendrá una NullPointerException si el String es nulo. Siempre puede usar if (s1! = Null && s1.length() == 0) ... De esta forma, su condicional se cortocircuitará al evaluar la longitud si s1 es nulo. – rtperson

+5

Sí, pero también lo hará s1.isEmpty() o s1.equals (""). – eaolson

0

Dados dos cadenas:

String s1 = "abc"; 
String s2 = "abc"; 

-o -

String s1 = new String("abc"); 
String s2 = new String("abc"); 

El operador == realiza en dos cheques Objetos de la identidad del objeto (que devuelve cierto si los dos operadores regresan al mismo objeto ejemplo). El comportamiento real de == aplicado a java.lang.Strings no siempre parece ser consistente debido al internamiento de cadenas.

En Java, las cadenas son interned (al menos parcialmente a discreción de la JVM). En cualquier momento, s1 y s2 pueden o no haberse internado para ser la misma referencia de objeto (suponiendo que tengan el mismo valor). Por lo tanto, s1 == s2 puede o no devolver verdadero, basándose únicamente en si s1 y s2 han sido internados.

Hacer que s1 y s2 sean cadenas vacías no tiene ningún efecto en esto: aún pueden haber sido o no internados.

En resumen, == puede o no devolver verdadero si s1 y s2 tienen el mismo contenido. s1.equals (s2) se garantiza que devuelve verdadero si s1 y s2 tienen el mismo contenido.

3

Use String.isEmpty() o StringUtils.isEmpty(String str) si necesita una verificación nula.

+0

Ojalá Java tuviera un String.Empty que pudiera establecer una cadena para que le gustara en C#. Haría que el método isEmpty() tuviera más sentido, y facilitaría la limpieza para hacer que una variable sea igual a la cadena vacía. – Knoxie

6

Respuesta corta

s1 == ""   // No! 
s1.equals("") // Ok 
s1.isEmpty()  // Ok: fast (from Java 1.6) 
"".equals(s1) // Ok: null safe 

Me aseguro s1 no es nulo y el uso de estaVacia().

Nota: la cadena vacía "" no es una cadena especial, pero cuenta como cualquier otro "valor".

Un poco más de tiempo responder

Las referencias a objetos String dependerá de la forma en que se crean:

objetos cadena creada usando el operador nueva siempre se refieren a objetos separados, incluso si se almacenan la misma secuencia de caracteres así:

String s1 = new String(""); 
String s2 = new String(""); 
s1 == s2 // false 

Objetos de cadena creados con el operador = seguido de un valor adjunto wh itin comillas dobles (= "valor") se almacenan en un grupo de objetos String: antes de crear un nuevo objeto en el grupo, se busca en el grupo un objeto con el mismo valor y se hace referencia a él si se encuentra.

String s1 = ""; // "" added to the pool 
String s2 = ""; // found "" in the pool, s2 will reference the same object of s1 
s1 == s2  // true 

Lo mismo es cierto para las cadenas creadas encierra un valor WHITIN comillas dobles ("valor"), por lo que:

String s1 = ""; 
s1 == "";  //true 

cadena es igual método comprueba tanto, es por eso que es seguro para escribir:

s1.equals(""); 

Esta expresión puede lanzar una NullPointerException si s1 == null, por lo que, si no comprobar nULL antes, es más seguro para escribir:

"".equals(s1); 

Por favor, lea también How do I compare strings in Java?

espero que puede ayudar a los usuarios no tan experimentados, que pueden encontrarse otras respuestas un poco demasiado complicados. :)

Cuestiones relacionadas