¿Debo usar string.isEmpty () o "" .equals (string)?

171

El título básicamente lo dice todo. Por lo general, estoy probando esto junto con un string == null, así que no estoy realmente preocupado por una prueba nula-segura. ¿Cuál debería usar?

String s = /* whatever */;
...
if (s == null || "".equals(s))
{
    // handle some edge case here
}

o

if (s == null || s.isEmpty())
{
    // handle some edge case here
}

En esa nota, ¿ isEmpty()hace algo más que return this.equals("");o return this.length() == 0;?

Matt Ball
fuente
26
Tenga en cuenta que solo isEmpty()es Java 6+.
ColinD
1
Podría hacer un método auxiliar Util.String.hasValue (String s) que verifica nulos, vacíos y espacios en blanco para manejar todos los casos.
Cloudanger
55
@ColinD Probablemente no sea un problema: J2SE 5.0 completó su período de finalización de la vida útil hace algún tiempo.
Tom Hawtin - entrada el
1
Otra cosa a considerar es "" .equals () toma Object como argumento, por lo que no obtendrá un error del compilador si el tipo de argumento cambia de String a otra cosa, para bien o para mal.
Paul Jackson

Respuestas:

251

El principal beneficio de "".equals(s)es que no necesita la verificación nula ( equalsverificará su argumento y devolverá falsesi es nula), que parece no importarle. Si no le preocupa sser nulo (o de lo contrario lo está comprobando), definitivamente lo usaría s.isEmpty(); muestra exactamente lo que está comprobando, le importa si sestá vacío o no , no si es igual a la cadena vacía

Michael Mrozek
fuente
29
Gracias por la explicación. ¡Ahora sé por qué favorecer "" .equals (str) sobre str.equals ("")! Siempre me preguntaba por qué otros usan esto con tanta frecuencia, pero no tomé en cuenta los valores nulos. Genial :-)
Peter Wippermann
10
En mi humilde opinión, la verificación nula todavía es necesaria en los ejemplos anteriores, ya que suponemos que la condición debe ser verdadera para el valor nulo. s == nulo || "" .equals (s)
mkorpela
55
@ Master.Aurora no, si se getValue()devuelve nulo, obtendría una NullPointerException cuando toString()se llamara
ataulm
12
@ RenniePet No es que haya magia involucrada. Si ses nulo, no puede invocar métodos, es nulo. ""nunca será nulo, por lo que puede invocar métodos de forma segura y equals()puede manejar el caso donde su argumento es nulo
Michael Mrozek
55
Una nota sobre el rendimiento: isEmpty()comprueba la longitud interna de una matriz privada, mientras que equals(Object anObject)hace mucho más (por ejemplo, comprobación instanceof). En cuanto al rendimiento, isEmpty()generalmente es más rápido.
Turing85
82

String.equals("")en realidad es un poco más lento que solo una isEmpty()llamada. Las cadenas almacenan una variable de recuento inicializada en el constructor, ya que las cadenas son inmutables.

isEmpty() compara la variable de recuento a 0, mientras que igual verificará el tipo, la longitud de la cadena y luego iterará sobre la cadena para comparar si los tamaños coinciden.

Entonces, para responder a su pregunta, ¡en isEmpty()realidad hará mucho menos! y eso es bueno

David Young
fuente
3
Creo que en este caso la diferencia no se aplica; nunca habrá una iteración sobre las cadenas para la comparación, porque los tamaños no coincidirán (a menos que la cadena esté realmente vacía, y luego no haya caracteres para iterar)
Michael Mrozek
2
Es cierto, pero con iguales, primero realiza una comprobación de referencia para ver si son el mismo objeto, luego una instancia de, luego una conversión a Cadena, una comprobación de longitud y, finalmente, la iteración. Si ambas cadenas estuvieran vacías, entonces sería solo una simple verificación de referencia.
David Young
el código fuente de la clase String está disponible java2s.com/Open-Source/Java-Document/6.0-JDK-Core/lang/java/…
David Young
1
@David enlace muerto; aquí hay un live docjar.com/html/api/java/lang/String.java.html#1011
Matt Ball
17

Una cosa que quizás desee considerar además de los otros problemas mencionados es que isEmpty()se introdujo en 1.6, por lo que si lo usa, no podrá ejecutar el código en Java 1.5 o inferior.

Fabian Steeg
fuente
44
Eso definitivamente no es una preocupación para mí.
Matt Ball
1
Además, esta respuesta es ahora hace 6 años. Espero que ya nadie tenga que usar nada antiguo como Java 1.5.
Misha Nasledov
1
De hecho, hay muchas cosas que pueden romperse al actualizar una versión de Java. Es menos crítico para una aplicación de fondo que se ejecuta en un gran servidor, pero sí importa para las aplicaciones cliente. Las bibliotecas gráficas y las estrategias de recolección de basura se ven afectadas a menudo por actualizaciones java mayores y menores. Además de eso, el software del cliente puede ejecutarse en varios sistemas operativos y, a veces, con memoria limitada, lo que significa que a menudo no tendrá el presupuesto / recursos para probar todo. - Sí, tengo clientes que aún siguen con Java 5 en 2017.
bvdb
15

Puede usar Apache commons StringUtils isEmpty () o isNotEmpty ().

Frijoles
fuente
1
@ 2019 y todavía necesitamos una biblioteca de terceros para esto: suspiro:
Adam
2

Realmente no importa. "".equals(str)Es más claro en mi opinión.

isEmpty()vuelve count == 0;

Kylar
fuente
47
Yo diría que str.isEmpty()es mucho más claro que "".equals(str). Se lee como lo que estás comprobando. Sin embargo, creo que es cuestión de opinión.
ColinD
77
Creo que algunas personas prefieren hacer "" .equals (str) para evitar NPE. Personalmente no me gusta porque preferiría verificar que la cadena no sea nula primero.
CoolBeans
2

Escribí una clase de probador que puede probar el rendimiento:

public class Tester
{
    public static void main(String[] args)
    {
        String text = "";

        int loopCount = 10000000;
        long startTime, endTime, duration1, duration2;

        startTime = System.nanoTime();
        for (int i = 0; i < loopCount; i++) {
            text.equals("");
        }
        endTime = System.nanoTime();
        duration1 = endTime - startTime;
        System.out.println(".equals(\"\") duration " +": \t" + duration1);

        startTime = System.nanoTime();
        for (int i = 0; i < loopCount; i++) {
            text.isEmpty();
        }
        endTime = System.nanoTime();
        duration2 = endTime - startTime;
        System.out.println(".isEmpty() duration "+": \t\t" + duration2);

        System.out.println("isEmpty() to equals(\"\") ratio: " + ((float)duration2 / (float)duration1));
    }
}

Descubrí que usar .isEmpty () tomó alrededor de la mitad del tiempo de .equals ("").

conapart3
fuente
Este no es un microbenchmark válido. Recomiendo encarecidamente utilizar Caliper o una herramienta de evaluación comparativa similar. stackoverflow.com/q/504103/139010
Matt Ball
¡Gracias por el consejo! Cuando tenga algo de tiempo libre, experimentaré con algunos micro benchmarking y actualizaré mi respuesta.
conapart3