(Cadena) o .toString ()?


89

Tengo un método con un Object oparámetro.

En este método, sé exactamente que hay una String"o" que no es nula. No es necesario verificar ni hacer nada más. Tengo que tratarlo exactamente como un Stringobjeto.

Solo por curiosidad, ¿qué es más barato, lanzarlo Stringo usarlo Object.toString()? ¿O es lo mismo por tiempo- / cpu- / mem- precio?

Actualización: el método acepta Objectporque es la implementación de una interfaz. No hay forma de cambiar el tipo de parámetro.

Y no puede ser nullen absoluto. Solo quería decir que no necesito verificar si está nulo o vacío. En mi caso, siempre hay una cadena no vacía.


1
En el mundo .NET, lo medimos y ToString () es más rápido. Dada la razón por la que esto es así, es casi seguro que lo mismo sea cierto para una JVM nerviosa.
Joshua

Respuestas:


73

La conversión a String es más barata ya que no requiere una llamada de función externa, solo una verificación de tipo interna.


4
¿Lo ha probado en varios JRE? He visto resultados sorprendentes para exactamente esta situación en .NET. Siendo realistas, dudo que el rendimiento importe en la vida real, pero el casting es mejor desde una perspectiva de codificación defensiva.
Jon Skeet

La llamada al método debería estar en línea. Usar genéricos para eliminar la conversión (explícita) sería lo mejor.
Tom Hawtin - tackline

@Jon Skeet: Estoy de acuerdo en que la diferencia en el rendimiento no será mucha. @Tom Hawtin: Dado que el tipo de objeto que se recibirá no se conoce en el momento de la compilación, no puedo ver cómo se puede insertar la llamada al método. ¿Puede aclarar por favor?
euphoria83

@ euphoria83: incluido en el compilador JIT, no en javac.
Michael Myers

En realidad, no, el método no se puede insertar. Solo se sabe que el tipo es Objeto y la implementación real depende del tipo de tiempo de ejecución. Cuál es más rápido aún depende de la implementación, pero por lo que recuerdo (en realidad lo probé con microbenchmark en un momento), la transmisión parece ser más rápida. Sin embargo, esta no es una respuesta obvia: la verificación de tipos no siempre es más rápida. Para el tipo de cadena, puede ser ya que es un objeto (no una interfaz), y uno final.
StaxMan

45

Usaría un yeso. Eso valida tu "conocimiento" de que es una cadena. Si por alguna razón termina con un error y alguien pasa algo que no sea una cadena, creo que sería mejor lanzar una excepción (lo que hará un elenco) que continuar ejecutando con datos defectuosos.



7

Si sabe que el Objeto o es una Cadena, diría que simplemente conviértalo en una Cadena y aplíquelo de esa manera. Llamar a toString () en un objeto que sabe con certeza que es una cadena podría agregar confusión.

Si Object o puede ser cualquier cosa que no sea String, deberá llamar a toString ().


Esta es la respuesta correcta para mí. ¿Por qué? Porque la conversión (string)Registry.GetValue...arroja una excepción para intentar transmitir un objeto Int32, mientras que Registry.GetValue...ToString()funciona como se esperaba.
gravedad

3

No me preocuparía demasiado el rendimiento, si esta operación se realiza incluso unos pocos miles de veces por segundo, no hay una diferencia tangible.

Sin embargo, me preocuparía "conocer" la entrada. Tiene un método que acepta un Objecty debe tratarlo como tal, es decir, no debe saber nada sobre el parámetro, aparte de que se adhiere a la Objectinterfaz, que tiene un toString()método. En este caso, sugeriría encarecidamente usar ese método en lugar de simplemente asumir algo.

Otoh, si la entrada es siempre bien Stringo null, simplemente cambiar el método de aceptar Strings, y comprobar de forma explícita nulls (que se debe hacer de todos modos al tratar con los no-primitivas ...)


Dije que mi pregunta no tiene un significado valioso :) Solo tengo curiosidad por saber qué es teóricamente más barato. Pero gracias de todos modos
Vugluskr

El costo dependerá de la eficiencia de la máquina virtual en las llamadas a métodos virtuales frente a la verificación de tipos. Eso es específico de la implementación.
Jon Skeet

2

Dado que el tipo de referencia es un objeto y todos los objetos tienen un toString () simplemente llame a object.toString (). String.toString () simplemente devuelve esto.

  • toString () es menos código para escribir.
  • toString () es menos código de bytes.
  • La fundición es una operación cara frente a una llamada polimórfica.
  • el elenco podría fallar.
  • Use String.valueOf (object) que solo llama a object.toString () si no es nulo.

1

Si lo que tiene en "o" es una cadena, entonces no hay mucha diferencia (probablemente la transmisión sea más rápida, pero eso es una implementación de VM / Biblioteca).

Si "o" puede no ser una Cadena, pero se supone que es una Cadena, entonces el elenco es lo que desea (pero debe hacer que el método tome una Cadena en lugar de un Objeto).

Si "o" puede ser de cualquier tipo, entonces debe usar toString, pero asegúrese de verificar primero si es nulo.

void foo(final Object o)
{
    final String str;

    // without this you would get a class cast exception
    // be wary of using instanceof though - it is usually the wrong thing to do
    if(o instanceof String)
    {
        str = (String)o;
    }    
}

o

void foo(final Object o)
{
    final String str;

    // if you are 100% sure that o is not null then you can get rid of the else
    if(o != null)
    {
        str = o.toString();
    }
}

Prefiero codificar el último como:

void foo(final Object o)
{
    final String str;

    if(o == null)
    {
        throw new IllegalArgumentException("o cannot be null");
    }

    str = o.toString();
}

Los primeros 2 fragmentos no se compilarán realmente (es posible que la finalvariable no se haya inicializado). Necesita un elseque arrojará una excepción o se inicializará stren algo.
Bruno Reis

1

Encontré curiosamente que el lanzamiento fue más lento que la búsqueda de vtable implícita en la llamada tostring.


1

No puede haber una 'cadena nula en o'. Si o es nulo, no contiene una cadena nula, simplemente es nulo. Simplemente marque o para nulo primero. Si lanza o llama a ToString () en nulo, se bloqueará.


2
La transmisión nula no se bloqueará. Ni siquiera lanzará una NullPointerException, solo llamará a null al nuevo tipo. :)
Bombe
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.