String.valueOf () vs. Object.toString ()

132

En Java, ¿hay alguna diferencia entre String.valueOf(Object)y Object.toString()? ¿Existe una convención de código específica para estos?

MCMastery
fuente
10
Los tipos primitivos no tienen un "toString" ... por lo que String.valueOfse usa. Para los objetos que anulan aString, creo que String.valueOf podría llamar a eso en su lugar. Aunque no estoy seguro de esa parte.
Brandon
@ Brandon Tienes razón, hace exactamente eso, excepto que comprueba nullprimero.
azurefrog
El primer comentario aquí creo que tiene más sentido si es correcto. Debe usar String.valueOf en ciertas situaciones en las que el objetivo es un tipo primitivo.
Donato

Respuestas:

177

De acuerdo con la documentación de Java , String.valueOf()devuelve:

si el argumento es null, entonces una cadena igual a "null"; de lo contrario, obj.toString()se devuelve el valor de .

Por lo tanto, no debería haber una diferencia, excepto una invocación de método adicional.

Además, en el caso de Object#toString, si la instancia es null, se NullPointerExceptionlanzará un , por lo que podría decirse que es menos seguro .

public static void main(String args[]) {  
    String str = null;
    System.out.println(String.valueOf(str));  // This will print a String equal to "null"        
    System.out.println(str.toString()); // This will throw a NullPointerException
} 
Kuba Rakoczy
fuente
66
Esta es la mejor respuesta. Lea y confíe en los javadocs, no en el código. (El código en principio podría ser diferente para diferentes versiones / lanzamientos de Java.)
Stephen C
77
@ Brandon - Incorrecto. Solo necesita cambiar si el comportamiento cambia de una manera que invalida el javadoc. 1) Las posibilidades de que eso suceda para este método son CERO. No harán un cambio que justifique un cambio en la especificación, y si lo hicieran , cambiarían la especificación. 2) No invalida mi consejo. Si lees el javadoc, ¡verás que el comportamiento documentado ha cambiado!
Stephen C
2
¿No sería más seguro el método que arroja la excepción ? Por lo general, cuando su código arroja una NullPointerException, es algo bueno. Puede que no se sienta bien para el desarrollador en este momento ("aww, no, ahora tengo que volver y arreglar mi código"), pero como se produjo el error, descubriste que necesitabas arreglar algo. Si se deja al revés, está exponiendo el "nulo" directamente al usuario y no se informa un error a menos que lo compruebe explícitamente, lo que me parece menos seguro.
Tim M.
1
Para ser claros, en realidad no se puede llamar String.valueOf(null), eso es un NPE. Solo funciona para objetos que son nulos.
Noumenon
1
Esa no es la explicación. El String.valueOf(null)realmente resuelve la valueOf(char[])sobrecarga. Esto se debe a que char[]es un tipo más específico que Object.
Stephen C
17

Las diferencias entre String.valueOf (Object) y Object.toString () son:

1) Si la cadena es nula,

String.valueOf(Object)regresará null, mientras Object::toString()que lanzará una excepción de puntero nulo.

public static void main(String args[]){  
    String str = null;

    System.out.println(String.valueOf(str));  // it will print null        
    System.out.println(str.toString()); // it will throw NullPointerException        
}  

2) Firma:

El método valueOf () de la clase String es estático. mientras que el método toString () de la clase String no es estático.

La firma o sintaxis del método valueOf () de la cadena se proporciona a continuación:

public static String valueOf(boolean b)  
public static String valueOf(char c)  
public static String valueOf(char[] c)  
public static String valueOf(int i)  
public static String valueOf(long l)  
public static String valueOf(float f)  
public static String valueOf(double d)  
public static String valueOf(Object o)

La firma o sintaxis del toString()método de cadena se da a continuación:

public String toString()
Shipra Sharma
fuente
13

En Java, ¿hay alguna diferencia entre String.valueOf (Object) y Object.toString ()?

Si. (¡Y más si consideras sobrecargar!)

Como explica el javadoc , String.valueOf((Object) null)se tratará como un caso especial por el valueOfmétodo y "null"se devolverá el valor . Por el contrario, null.toString()solo le dará un NPE.

Sobrecarga

Resulta que String.valueOf(null)(tenga en cuenta la diferencia!) Hace dar una NPE ... a pesar de la javadoc. La explicación es oscura:

  1. Hay varias sobrecargas de String.valueOf, pero hay dos que son relevantes aquí: String.valueOf(Object)y String.valueOf(char[]).

  2. En la expresión String.valueOf(null), ambas sobrecargas son aplicables , ya nullque la asignación es compatible con cualquier tipo de referencia.

  3. Cuando hay dos o más sobrecargas aplicables , el JLS dice que se elige la sobrecarga para el tipo de argumento más específico .

  4. Como char[]es un subtipo de Object, es más específico .

  5. Por lo tanto, String.valueOf(char[])se llama la sobrecarga.

  6. String.valueOf(char[])lanza un NPE si su argumento es una matriz nula. A diferencia String.valueOf(Object), no se trata nullcomo un caso especial.

(Puede confirmar esto usando javap -cpara examinar el código de un método que tiene una String.valueOf(null)llamada. Observe la sobrecarga que se usa para la llamada).

Otro ejemplo ilustra la diferencia en la valueOf(char[])sobrecarga aún más claramente:

char[] abc = new char[]('a', 'b', 'c');
System.out.println(String.valueOf(abc));  // prints "abc"
System.out.println(abc.toString());       // prints "[C@...."

¿Existe una convención de código específica para estos?

No.

Utilice el que sea más apropiado para los requisitos del contexto en el que lo está utilizando. (¿ Necesita el formato para trabajar null?)

Nota: eso no es una convención de código. Es solo programación de sentido común. Es más importante que su código sea correcto que seguir alguna convención estilística o dogma de "mejores prácticas".


Opinión personal:

Algunos desarrolladores adquieren el mal hábito (IMO) de "defenderse" de los nulos. Entonces ve muchas pruebas de nulos y trata los nulos como casos especiales. La idea parece ser evitar que suceda NPE.

Creo que esta es una mala idea. En particular, creo que es una mala idea si lo que haces cuando encuentras un nulles tratar de "hacer el bien" ... sin tener en cuenta por qué había un nullallí.

En general, es mejor evitar nullestar allí en primer lugar ... a menos que nulltenga un significado muy específico en su aplicación o diseño de API. Entonces, en lugar de evitar el NPE con mucha codificación defensiva, es mejor dejar que ocurra el NPE, y luego rastrear y corregir la fuente de lo inesperado nullque desencadenó el NPE.

Entonces, ¿cómo se aplica esto aquí?

Bueno, si lo piensas bien, usar String.valueOf(obj) podría ser una forma de "hacer el bien". Eso debe ser evitado. Si es inesperado objestar nullen el contexto, es mejor usarlo obj.toString().

Stephen C
fuente
5

La mayoría ya ha sido mencionada por otras respuestas, pero solo la agrego para completar:

  1. Las primitivas no tienen una, .toString()ya que no son una implementación de la Objectclase, por lo que solo String.valueOfse pueden usar.
  2. String.valueOftransformará un objeto dado que está nullen la cadena "null", mientras .toString()que arrojará un NullPointerException.
  3. El compilador lo usará String.valueOfpor defecto cuando se use algo así String s = "" + (...);. Es por eso Object t = null; String s = "" + t;que resultará en la Cadena "null", y no en un NPE. EDITAR: En realidad, usará el StringBuilder.append, no String.valueOf. Ignora lo que dije aquí.

Además de esos, aquí hay un caso de uso donde String.valueOfy .toString()tienen diferentes resultados:

Digamos que tenemos un método genérico como este:

public static <T> T test(){
  String str = "test";
  return (T) str;
}

Y lo vamos a llamar con un Integertipo como este: Main.<Integer>test().

Cuando creamos una cadena con String.valueOfella funciona bien:

String s1 = String.valueOf(Main.<Integer>test());
System.out.println(s1);

Esto dará salida testa STDOUT.

Sin .toString()embargo, no funcionará:

String s2 = (Main.<Integer>test()).toString();
System.out.println(s2);

Esto dará como resultado el siguiente error:

java.lang.ClassCastException: la clase java.lang.Stringno se puede enviar a clasejava.lang.Integer

Pruébalo en línea.

En cuanto a por qué, puedo referirme a esta pregunta separada y sus respuestas . En resumen, sin embargo:

  • Cuando se utiliza .toString()por primera vez compilará y evaluar el objeto, donde el elenco a T(que es una Stringde Integerfundido en este caso) dará lugar a la ClassCastException.
  • Al usarlo String.valueOfverá el genérico Tcomo Objectdurante la compilación y ni siquiera le importa que sea un Integer. Entonces lanzará un Objectto Object(que el compilador simplemente ignora). Luego lo usará String.valueOf(Object), dando Stringcomo resultado lo esperado. Entonces, a pesar de String.valueOf(Object)que hará un .toString()parámetro interno, ya hemos omitido el reparto y se lo trata como un Object, así que hemos evitado lo ClassCastExceptionque ocurre con el uso de .toString().

Solo pensé que valía la pena mencionar esta diferencia adicional entre String.valueOfy .toString()aquí también.

Kevin Cruijssen
fuente
La última vez que me importó esto, que habría sido alrededor de JDK 1.2, ("" + x)compilado String.valueOf(x), pero cualquier cosa más complicada usaba un StringBuffer(no teníamos StringBuilderentonces).
Neil
4

String.valueOf(Object)y Object.toString()son literalmente lo mismo.

Si echa un vistazo a la implementación de String.valueOf (Object) , verá que String.valueOf(Object)es básicamente una invocación nula-segura del toString()objeto apropiado:

Returns the string representation of the Object argument.

Parameters:
    obj an Object.
Returns:
    if the argument is null, then a string equal to "null"; 
    otherwise, the value of obj.toString() is returned.
See also:
    Object.toString()

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}
azurefrog
fuente
No es cierto, use valueOf y toString en una matriz de caracteres y deleite sus ojos.
Artanis
3

La diferencia más importante es la forma en que manejan las referencias de cadena nulas.

String str = null;
System.out.println("String.valueOf gives : " + String.valueOf(str));//Prints null
System.out.println("String.toString gives : " + str.toString());//This would throw a NullPointerExeption
Abdullah Khan
fuente
1

Cuando el argumento es null, los String.valueOfretornos "null", pero Object.toStringarroja NullPointerException, esa es la única diferencia.

Everv0id
fuente
0

Hay una diferencia importante más entre los dos métodos es cuando el objeto que estamos convirtiendo es una matriz.

Cuando convierte una matriz usando Object.toString () obtendrá algún tipo de valor basura (@ seguido del código hash de la matriz).

Para obtener un toString () legible para humanos, debe usar String.valueOf (char []); tenga en cuenta que este método solo funciona para Array de tipo char. Recomendaría usar Arrays.toString (Object []) para convertir matrices a String.

La segunda diferencia es cuando el objeto es nulo, ValueOf () devuelve un String "nulo", mientras que toString () devolverá una excepción de puntero nulo.

Chintan Thakker
fuente
Hola @Tom, esto es cierto para una matriz de cualquier tipo. Sin embargo, si está utilizando Arrays.toString (Object []), puede convertir una matriz de cualquier tipo a cadena.
chintan thakker
Hola, @Tom Object.toString () que devuelve un valor basura es verdadero para una matriz de cualquier tipo, tienes razón en que String.valueOf (Array) dará una cadena correcta solo para una matriz de tipo char. Debería haber mencionado que, gracias, lo editaré.
Chintan Thakker
1
Ese no es un valor basura, es el nombre de clase y el código hash ( JavaDoc ).
Tom
-1

No puedo decir exactamente cuál es la diferencia, pero parece haber una diferencia cuando se opera a nivel de byte. En el siguiente escenario de cifrado, Object.toString () produjo un valor que no se pudo descifrar, mientras que String.valueOf () funcionó según lo previsto ...

private static char[] base64Encode(byte[] bytes) 
{   
    return Base64.encode(bytes);
}

private static String encrypt(String encrypt_this) throws GeneralSecurityException, UnsupportedEncodingException 
{
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
    SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
    Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
    pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));

     //THIS FAILED when attempting to decrypt the password
    //return base64Encode(pbeCipher.doFinal(encrypt_this.getBytes("UTF-8"))).toString(); 

    //THIS WORKED
    return String.valueOf(base64Encode(pbeCipher.doFinal(encrypt_this.getBytes("UTF-8"))));
}//end of encrypt()
Chris Walters
fuente
¿Por qué falló? ¿Cuál es el problema?
Yousha Aleayoub
La explicación es que en realidad estás llamando en valueOf(char[])lugar de valueOf(Object). El comportamiento de valueOf(char[])es significativamente diferente a char[].toString(). Pero de cualquier manera, esta respuesta no es apropiada porque está llamando a una sobrecarga diferente a la pregunta sobre la que pregunta.
Stephen C
-2

A continuación se muestra la implementación de java.lang.String.valueOf como se describe en la fuente de jdk8u25. Entonces, según mi comentario, no hay diferencia. Se llama "Object.toString". Para los tipos primitivos, lo envuelve en su forma de objeto y lo llama "toString".

Vea abajo:

/*
 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */


    public static String valueOf(Object obj) {
        return (obj == null) ? "null" : obj.toString();
    }

    public static String valueOf(char data[]) {
        return new String(data);
    }

    public static String valueOf(char data[], int offset, int count) {
        return new String(data, offset, count);
    }

    public static String copyValueOf(char data[], int offset, int count) {
        return new String(data, offset, count);
    }

    public static String copyValueOf(char data[]) {
        return new String(data);
    }

    public static String valueOf(boolean b) {
        return b ? "true" : "false";
    }

    public static String valueOf(char c) {
        char data[] = {c};
        return new String(data, true);
    }

    public static String valueOf(int i) {
        return Integer.toString(i);
    }

    public static String valueOf(long l) {
        return Long.toString(l);
    }

    public static String valueOf(float f) {
        return Float.toString(f);
    }

    public static String valueOf(double d) {
        return Double.toString(d);
    }
Brandon
fuente