String.valueOf () contre Object.toString ()

132

En Java, y a-t-il une différence entre String.valueOf(Object)et Object.toString()? Existe-t-il une convention de code spécifique pour ceux-ci?

MCMastère
la source
10
Les types primitifs n'ont pas de "toString" .. donc String.valueOfest utilisé. Pour les objets qui remplacent toString, je pense que String.valueOf pourrait appeler cela à la place. Pas sûr de cette partie cependant.
Brandon
@Brandon Vous avez raison, il fait exactement cela, sauf qu'il vérifie d' nullabord.
azurefrog
Le premier commentaire ici, je pense, a le plus de sens s'il est correct. Vous devez utiliser String.valueOf dans certaines situations où la cible est un type primitif.
Donato

Réponses:

177

Selon la documentation Java , String.valueOf()renvoie:

si l'argument est null, alors une chaîne égale à "null"; sinon, la valeur de obj.toString()est renvoyée.

Il ne devrait donc pas vraiment y avoir de différence, sauf pour un appel de méthode supplémentaire.

De plus, dans le cas de Object#toString, si l'instance est null, un NullPointerExceptionsera jeté, donc sans doute, c'est moins sûr .

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
la source
6
C'est la meilleure réponse. Lisez et comptez sur les javadocs, pas sur le code. (Le code pourrait en principe être différent pour différentes versions / versions de Java.)
Stephen C
7
@Brandon - Incorrect. Il ne doit changer que si le comportement change d'une manière qui invalide le javadoc. 1) Les chances que cela se produise pour cette méthode sont nulles. Ils ne vont pas faire un changement qui justifie un changement dans les spécifications, et s'ils le faisaient ils seraient changer les spécifications. 2) Cela n'invalide pas mon avis. Si vous lisez le javadoc, vous verrez que le comportement documenté a changé!
Stephen C
2
La méthode qui lève l'exception ne serait-elle pas plus sûre? Habituellement, lorsque votre code lance une exception NullPointerException, c'est en quelque sorte une bonne chose. Cela ne fait peut-être pas plaisir au développeur sur le moment ("aww, non, maintenant je dois revenir en arrière et corriger mon code"), mais comme l'erreur a été générée, vous avez découvert que vous deviez réparer quelque chose. Dans l'autre sens, vous exposez le "null" directement à l'utilisateur et n'obtenez pas une erreur signalée à moins que vous n'en vérifiiez explicitement une, ce qui me semble moins sûr.
Tim M.
1
Juste pour être clair, vous ne pouvez pas appeler String.valueOf(null), c'est un NPE. Cela ne fonctionne que pour les objets qui sont nuls.
Noumenon
1
Ce n'est pas l'explication. Le String.valueOf(null)résout réellement à la valueOf(char[])surcharge. C'est parce que char[]c'est un type plus spécifique que Object.
Stephen C du
17

Les différences entre String.valueOf (Object) et Object.toString () sont:

1) Si la chaîne est nulle,

String.valueOf(Object)retournera null, alors que Object::toString()lancera une exception de pointeur nul.

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) Signature:

La méthode valueOf () de la classe String est statique. alors que la méthode toString () de la classe String n'est pas statique.

La signature ou la syntaxe de la méthode valueOf () de la chaîne est donnée ci-dessous:

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 signature ou la syntaxe de la toString()méthode string est donnée ci-dessous:

public String toString()
Shipra Sharma
la source
13

En Java, y a-t-il une différence entre String.valueOf (Object) et Object.toString ()?

Oui. (Et plus encore si vous envisagez de surcharger!)

Comme l' explique le javadoc , String.valueOf((Object) null)sera traité comme un cas particulier par la valueOfméthode et la valeur "null"est retournée. En revanche, null.toString()vous donnera juste un NPE.

Surcharge

Il se trouve que String.valueOf(null)(notez la différence!) Ne donne un NPE ... malgré la javadoc. L'explication est obscure:

  1. Il existe un certain nombre de surcharges de String.valueOf, mais il y en a deux qui sont pertinentes ici: String.valueOf(Object)et String.valueOf(char[]).

  2. Dans l'expression String.valueOf(null), ces deux surcharges sont applicables , car l' nullaffectation est compatible avec n'importe quel type de référence.

  3. Lorsqu'il y a au moins deux surcharges applicables , le JLS indique que la surcharge pour le type d'argument le plus spécifique est choisie.

  4. Puisqu'il char[]s'agit d'un sous-type de Object, il est plus spécifique .

  5. Par conséquent, la String.valueOf(char[])surcharge est appelée.

  6. String.valueOf(char[])lève un NPE si son argument est un tableau nul. Contrairement à String.valueOf(Object)cela, il ne s'agit pas nulld'un cas particulier.

(Vous pouvez le confirmer en utilisant javap -cpour examiner le code d'une méthode qui a un String.valueOf(null)appel. Observez la surcharge qui est utilisée pour l'appel.)

Un autre exemple illustre valueOf(char[])encore plus clairement la différence de surcharge:

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

Existe-t-il une convention de code spécifique pour ceux-ci?

Non.

Utilisez celui qui convient le mieux aux exigences du contexte dans lequel vous l'utilisez. (Avez-vous besoin du formatage pour travailler null?)

Remarque: ce n'est pas une convention de code. C'est juste une programmation de bon sens. Il est plus important que votre code soit correct que de suivre une convention stylistique ou un dogme des «meilleures pratiques».


Opinion personnelle:

Certains développeurs prennent la mauvaise habitude (IMO) de "se défendre" contre les nulls. Vous voyez donc de nombreux tests pour les valeurs nulles et le traitement des valeurs nulles comme des cas spéciaux. L'idée semble être d'empêcher les NPE de se produire.

Je pense que c'est une mauvaise idée. En particulier, je pense que c'est une mauvaise idée si ce que vous faites quand vous trouvez un nullest d'essayer de "faire du bien" ... sans tenir compte de la raison pour laquelle il y avait un nulllà.

En général, il vaut mieux éviter d' nullêtre là en premier lieu ... à moins que le nulln'ait une signification très spécifique dans votre application ou dans la conception de votre API. Ainsi, plutôt que d'éviter le NPE avec beaucoup de codage défensif, il est préférable de laisser le NPE se produire, puis de localiser et de corriger la source de l'inattendu nullqui a déclenché le NPE.

Alors, comment cela s'applique-t-il ici?

Eh bien, si vous y réfléchissez, utiliser String.valueOf(obj) pourrait être un moyen de "faire du bien". C'est à éviter. S'il est inattendu objd'être nulldans le contexte, il vaut mieux utiliser obj.toString().

Stephen C
la source
5

La plupart ont déjà été mentionnés par d'autres réponses, mais je l'ajoute simplement pour être complet:

  1. Les primitives n'ont pas de .toString()car elles ne sont pas une implémentation de Object-class, elles ne String.valueOfpeuvent donc être utilisées.
  2. String.valueOftransformera un objet donné qui est nullen String "null", alors que .toString()lancera un NullPointerException.
  3. Le compilateur utilisera String.valueOfpar défaut quand quelque chose comme String s = "" + (...);est utilisé. C'est pourquoi Object t = null; String s = "" + t;aboutira à la chaîne "null", et non à un NPE. EDIT: En fait, il utilisera le StringBuilder.append, non String.valueOf. Alors ignorez ce que j'ai dit ici.

En plus de ceux-ci, voici en fait un cas d'utilisation où String.valueOfet .toString()ont des résultats différents:

Disons que nous avons une méthode générique comme celle-ci:

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

Et nous allons l' appeler avec un Integergenre comme celui - ci: Main.<Integer>test().

Lorsque nous créons une chaîne avec String.valueOfcela fonctionne bien:

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

Cela sortira testvers STDOUT.

Avec un .toString()cependant, cela ne fonctionnera pas:

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

Cela entraînera l'erreur suivante:

java.lang.ClassCastException: la classe java.lang.Stringne peut pas être convertie en classejava.lang.Integer

Essayez-le en ligne.

Quant à savoir pourquoi, je peux me référer à cette question séparée et à ses réponses . Bref cependant:

  • Lors de l' utilisation , .toString()il va d' abord compiler et évaluer l'objet, où la distribution de T( ce qui est Stringde Integercasting dans ce cas) entraînera la ClassCastException.
  • Lors de son utilisation, String.valueOfil verra le générique Tcomme Objectlors de la compilation et ne se souciera même pas que ce soit un fichier Integer. Donc, il convertira un Objectvers Object(que le compilateur ignore tout simplement). Ensuite, il utilisera String.valueOf(Object), résultant en un Stringcomme prévu. Ainsi, même si le String.valueOf(Object)fera un .toString()sur le paramètre en interne, nous avons déjà ignoré le cast et il est traité comme un Object, nous avons donc évité ce ClassCastExceptionqui se produit avec l'utilisation de .toString().

Je pensais juste qu'il valait la peine de mentionner cette différence supplémentaire entre String.valueOfet .toString()ici également.

Kevin Cruijssen
la source
La dernière fois que je me suis soucié de cela, cela aurait été autour de JDK 1.2, ("" + x)compilé en String.valueOf(x), mais quelque chose de plus compliqué a utilisé un StringBuffer(nous n'avions pas StringBuilderalors).
Neil
4

String.valueOf(Object)et Object.toString()sont littéralement la même chose.

Si vous jetez un œil à l'implémentation de String.valueOf (Object) , vous verrez qu'il ne String.valueOf(Object)s'agit en gros que d'un appel de null-safe toString()de l'objet approprié:

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
la source
Ce n'est pas vrai, utilisez à la fois valueOf et toString sur un tableau de caractères et régalez vos yeux.
Artanis
3

La différence la plus importante est la façon dont ils gèrent les références de chaîne nulles.

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
la source
1

Quand l'argument est null, le String.valueOfretourne "null", mais Object.toStringjette NullPointerException, c'est la seule différence.

Everv0id
la source
0

Il existe une autre différence majeure entre les deux méthodes lorsque l'objet que nous convertissons est un tableau.

Lorsque vous convertissez un tableau en utilisant Object.toString (), vous obtiendrez une sorte de valeur de garbage (@ suivi du hashcode du tableau).

Pour obtenir un toString () lisible par l'homme, vous devez utiliser String.valueOf (char []); Veuillez noter que cette méthode ne fonctionne que pour Array de type char. Je recommanderais d'utiliser Arrays.toString (Object []) pour convertir des tableaux en String.

La deuxième différence est que lorsque l'objet est nul, ValueOf () renvoie une chaîne "null", tandis que toString () renverra une exception de pointeur nul.

chintan thakker
la source
Salut @Tom c'est vrai pour un tableau de n'importe quel type, cependant si vous utilisez Arrays.toString (Object []), vous pouvez convertir un tableau de n'importe quel type en chaîne.
chintan thakker
Salut @Tom Object.toString () renvoyant une valeur de garbage est vrai pour un tableau de tout type, vous avez raison de dire que String.valueOf (Array) donnera une chaîne correcte uniquement pour un tableau de type char. J'aurais dû mentionner que, merci, je vais le modifier.
chintan thakker
1
Ce n'est pas une valeur de garbage, c'est le nom de la classe et le hashcode ( JavaDoc ).
Tom
-1

Je ne peux pas dire exactement quelle est la différence, mais il semble y avoir une différence lors du fonctionnement au niveau des octets. Dans le scénario de chiffrement suivant, Object.toString () a produit une valeur qui n'a pas pu être déchiffrée alors que String.valueOf () fonctionnait comme prévu ...

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
la source
Pourquoi a échoué? quel est le problème?
Yousha Aleayoub
L'explication est que vous appelez valueOf(char[])plutôt que valueOf(Object). Le comportement de valueOf(char[])est très différent de char[].toString(). Mais de toute façon, cette réponse n'est pas à propos car vous appelez une surcharge différente de celle sur laquelle la question pose la question.
Stephen C
-1

Et dans la plupart des cas, il est préférable de renvoyer la valeur NPE plutôt que "null"

Markkan
la source
-2

Le tableau ci-dessous montre l'implémentation de java.lang.String.valueOf comme décrit dans la source de jdk8u25. Donc, selon mon commentaire, il n'y a pas de différence. Il appelle "Object.toString". Pour les types primitifs, il l'enveloppe dans sa forme objet et appelle "toString" dessus.

Voir ci-dessous:

/*
 * 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
la source