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


132

In Java, c'è qualche differenza tra String.valueOf(Object)e Object.toString()? Esiste una convenzione di codice specifica per questi?


10
I tipi primitivi non hanno un "toString" .. quindi String.valueOfviene utilizzato. Per gli oggetti che hanno la precedenza su String, penso che String.valueOf potrebbe chiamarlo invece. Non sono sicuro di quella parte però.
Brandon,

@Brandon Hai ragione, lo fa esattamente, tranne che controlla per nullprimo.
Azurefrog,

Il primo commento qui penso che abbia più senso se è corretto. È necessario utilizzare String.valueOf in determinate situazioni in cui la destinazione è di tipo primitivo.
Donato,

Risposte:


177

Secondo la documentazione Java , String.valueOf()restituisce:

se l'argomento è null, allora una stringa uguale a "null"; in caso contrario, obj.toString()viene restituito il valore di .

Quindi non dovrebbe esserci davvero alcuna differenza se non per un'ulteriore chiamata al metodo.

Inoltre, nel caso di Object#toString, se l'istanza lo è null, NullPointerExceptionverrà generata una volontà, quindi probabilmente è meno sicura .

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
} 

6
Questa è la risposta migliore Leggi e fai affidamento sul javadocs, non sul codice. (Il codice potrebbe in linea di principio essere diverso per le diverse versioni / versioni di Java.)
Stephen C

7
@Brandon: errato. Deve solo cambiare se il comportamento cambia in modo da invalidare il javadoc. 1) Le possibilità che ciò accada per questo metodo sono ZERO. Essi non fare un cambiamento che giustificato un cambiamento nelle specifiche, e se lo facessero allora avrebbero cambiare le specifiche. 2) Non invalida il mio consiglio. Se leggi il javadoc, vedrai che il comportamento documentato è cambiato!
Stephen C

2
Il metodo che genera l'eccezione non sarebbe più sicuro? Di solito, quando il tuo codice genera una NullPointerException, è una buona cosa. Al momento potrebbe non essere piacevole per lo sviluppatore ("aww, no, ora devo tornare indietro e correggere il mio codice"), ma poiché l'errore è stato generato, hai scoperto che dovevi risolvere qualcosa. A sinistra, stai esponendo il "null" direttamente all'utente e non ricevi un errore se non ne controlli esplicitamente uno, il che mi sembra meno sicuro.
Tim M.

1
Giusto per essere chiari, non puoi davvero chiamare String.valueOf(null), questo è un NPE. Funziona solo con oggetti nulli.
Noumenon,

1
Questa non è la spiegazione. Il String.valueOf(null)risolve effettivamente al valueOf(char[])sovraccarico. Questo perché char[]è un tipo più specifico di Object.
Stephen C,

17

Le differenze tra String.valueOf (Object) e Object.toString () sono:

1) Se la stringa è nulla,

String.valueOf(Object)verrà restituito null, mentre Object::toString()verrà generata un'eccezione puntatore null.

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:

Il metodo valueOf () della classe String è statico. mentre il metodo toString () della classe String non è statico.

La firma o la sintassi del metodo valueOf () della stringa è riportata di seguito:

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 la sintassi del toString()metodo della stringa è riportata di seguito:

public String toString()

13

In Java, c'è qualche differenza tra String.valueOf (Object) e Object.toString ()?

Sì. (E ancora di più se consideri il sovraccarico!)

Come spiega javadoc , String.valueOf((Object) null)verrà trattato come un caso speciale dal valueOfmetodo e il valore "null"verrà restituito. Al contrario, null.toString()ti darà solo un NPE.

Sovraccarico

Si scopre che String.valueOf(null)(si noti la differenza!) Fa dare una NPE ... nonostante il javadoc. La spiegazione è oscura:

  1. Ci sono una serie di sovraccarichi di String.valueOf, ma ce ne sono due che sono rilevanti qui: String.valueOf(Object)e String.valueOf(char[]).

  2. Nell'espressione String.valueOf(null)sono applicabili entrambi questi sovraccarichi , poiché l' nullassegnazione è compatibile con qualsiasi tipo di riferimento.

  3. Quando ci sono due o più sovraccarichi applicabili , JLS afferma che viene scelto il sovraccarico per il tipo di argomento più specifico .

  4. Poiché char[]è un sottotipo di Object, è più specifico .

  5. Pertanto String.valueOf(char[])viene chiamato il sovraccarico.

  6. String.valueOf(char[])genera un NPE se il suo argomento è un array null. Diversamente String.valueOf(Object), non tratta nullun caso speciale.

(È possibile confermare ciò utilizzando javap -cper esaminare il codice di un metodo che ha una String.valueOf(null)chiamata. Osservare il sovraccarico utilizzato per la chiamata.)

Un altro esempio illustra la differenza nel valueOf(char[])sovraccarico ancora più chiaramente:

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

Esiste una convenzione di codice specifica per questi?

No.

Utilizzare ciò che è sempre più appropriato ai requisiti del contesto in cui lo si sta utilizzando. (Hai bisogno della formattazione per cui lavorarenull ?)

Nota: questa non è una convenzione di codice. È solo una programmazione di buon senso. È più importante che il codice sia corretto piuttosto che seguire una convenzione stilistica o un dogma di "best practice".


Opinione personale:

Alcuni sviluppatori acquisiscono la cattiva abitudine (IMO) di "difendere" dai null. Quindi vedete molti test per i null e trattiamo i null come casi speciali. L'idea sembra impedire che accada l'NPE.

Penso che questa sia una cattiva idea. In particolare, penso che sia una cattiva idea se quello che fai quando trovi un nullè cercare di "fare del bene" ... senza considerare il motivo per cui c'era un nulllì.

In generale, è meglio evitare di nullessere lì in primo luogo ... a meno che non nullabbia un significato molto specifico nella tua applicazione o progettazione API. Quindi, piuttosto che evitare l'NPE con molta codifica difensiva, è meglio lasciare che l'NPE accada, quindi rintracciare e riparare l'origine dell'imprevisto nullche ha innescato l'NPE.

Quindi, come si applica qui?

Bene, se ci pensate, usare String.valueOf(obj) potrebbe essere un modo per "fare del bene". Questo è da evitare. Se è inaspettato objessere nullnel contesto, è meglio usarlo obj.toString().


5

La maggior parte è già stata menzionata da altre risposte, ma la aggiungo per completezza:

  1. I primitivi non hanno un .toString()dato che non sono un'implementazione della Objectclasse, quindi soloString.valueOf possono essere utilizzati solo.
  2. String.valueOftrasformerà un determinato oggetto che è nullnella stringa "null", mentre .toString()lancerà aNullPointerException .
  3. Il compilatore utilizzerà String.valueOfper impostazione predefinita quando String s = "" + (...);viene utilizzato qualcosa di simile . Questo è il motivo Object t = null; String s = "" + t;per cui risulterà nella stringa "null"e non in un NPE. EDIT: In realtà, utilizzerà StringBuilder.append, no String.valueOf. Quindi ignora quello che ho detto qui.

Oltre a questi, qui è in realtà un caso d'uso in cui String.valueOfe .toString()hanno risultati diversi:

Diciamo che abbiamo un metodo generico come questo:

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

E che chiameremo con un Integertipo come questo: Main.<Integer>test().

Quando creiamo una stringa con String.valueOfessa funziona benissimo:

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

Questo verrà emesso testsu STDOUT.

Con un .toString()tuttavia, non funzionerà:

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

Ciò comporterà il seguente errore:

java.lang.ClassCastException: la classe java.lang.Stringnon può essere trasmessa alla classejava.lang.Integer

Provalo online.

Per quanto riguarda il motivo, posso fare riferimento a questa domanda separata e alle sue risposte . In breve però:

  • Quando si utilizza .toString()esso deve prima elaborare e valutare l'oggetto, in cui il cast T(che è un Stringa Integergetto in questo caso) comporterà il ClassCastException.
  • Quando lo usi String.valueOfvedrà il generico Tcome Objectdurante la compilazione e non si preoccupa nemmeno che sia un Integer. Così sarà lanciare un Objecta Object(che il compilatore semplicemente ignora). Quindi utilizzerà String.valueOf(Object), risultando Stringcome previsto. Quindi, anche se String.valueOf(Object)eseguirà .toString()internamente un parametro, abbiamo già ignorato il cast e trattato come un Object, quindi abbiamo evitato ClassCastExceptionciò che si verifica con l'uso di .toString().

Ho pensato che valesse la pena menzionare questa ulteriore differenza tra String.valueOfe anche .toString()qui.


L'ultima volta che mi sono preoccupato di questo, che sarebbe stato intorno a JDK 1.2, ("" + x)compilato String.valueOf(x), ma qualcosa di più complicato ha usato un StringBuffer(non avevamo StringBuilderallora).
Neil,

4

String.valueOf(Object)e Object.toString()sono letteralmente la stessa cosa.

Se dai un'occhiata all'implementazione di String.valueOf (Object) , noterai che String.valueOf(Object)è fondamentalmente solo una invocazione nulla-sicura toString()dell'oggetto appropriato:

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();
}

Non è vero, usa sia valueOf che toString su un array di caratteri e goditi i tuoi occhi.
Artanis,

3

La differenza più importante è il modo in cui gestiscono i riferimenti String null.

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

1

Quando l'argomento è null, i String.valueOfritorni "null", ma Object.toStringgenera NullPointerException, questa è l'unica differenza.


0

C'è ancora una differenza importante tra i due metodi quando l'oggetto che stiamo convertendo è un array.

Quando converti un array usando Object.toString () otterrai una sorta di valore garbage (@ seguito da hashcode dell'array).

Per ottenere un toString () leggibile dall'uomo, è necessario utilizzare String.valueOf (char []); per favore nota che questo metodo funziona solo per array di tipo char. Consiglierei di utilizzare Arrays.toString (Object []) per convertire array in String.

La seconda differenza è quando l'oggetto è null, ValueOf () restituisce una stringa "null", mentre toString () restituirà un'eccezione puntatore null.


Salve @ Tom, questo vale per un array di qualsiasi tipo, tuttavia se si utilizza Arrays.toString (Object []), è possibile convertire un array di qualsiasi tipo in stringa.
Chintan Thakker,

Ciao @Tom Object.toString () che restituisce un valore di immondizia è vero per un array di qualsiasi tipo, hai ragione che String.valueOf (Array) fornirà una stringa corretta solo per un array di tipo char. Avrei dovuto menzionare che, grazie, lo modificherò.
Chintan Thakker,

1
Questo non è un valore di immondizia, è il nome di classe e l'hashcode ( JavaDoc ).
Tom,

-1

Non posso dire esattamente quale sia la differenza, ma sembra esserci una differenza quando si opera a livello di byte. Nel seguente scenario di crittografia Object.toString () ha prodotto un valore che non è stato possibile decrittografare mentre String.valueOf () ha funzionato come 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()

Perché fallito? qual è il problema?
Yousha Aleayoub,

La spiegazione è che in realtà stai chiamando valueOf(char[])piuttosto che valueOf(Object). Il comportamento di valueOf(char[])è significativamente diverso da char[].toString(). Ma in entrambi i casi, questa risposta non è a proposito perché stai chiamando un sovraccarico diverso da quello della domanda.
Stephen C,

-2

Di seguito viene mostrata l'implementazione per java.lang.String.valueOf come descritto nell'origine per jdk8u25. Quindi, secondo il mio commento, non c'è differenza. Chiama "Object.toString". Per i tipi primitivi, lo avvolge nella sua forma di oggetto e chiama "toString" su di esso.

Vedi sotto:

/*
 * 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);
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.