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

132

Em Java, existe alguma diferença entre String.valueOf(Object)e Object.toString()? Existe uma convenção de código específica para eles?

MCMastery
fonte
10
Tipos primitivos não têm um "toString" .. então String.valueOfé usado. Para objetos que substituem toString, acho que String.valueOf pode chamar isso. Não tenho certeza sobre essa parte embora.
Brandon
@Brandon Você está correto, faz exatamente isso, exceto pelo fato de verificar nullprimeiro.
Azurefrog
Acho que o primeiro comentário aqui faz mais sentido se estiver correto. Você deve usar String.valueOf em determinadas situações em que o destino é um tipo primitivo.
Donato

Respostas:

177

De acordo com a documentação Java , String.valueOf()retorna:

se o argumento for null, uma sequência igual a "null"; caso contrário, o valor de obj.toString()é retornado.

Portanto, realmente não deve haver diferença, exceto por uma invocação de método adicional.

Além disso, no caso de Object#toString, se a instância for null, a NullPointerExceptionserá lançada, então, sem dúvida, é 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
fonte
6
Esta é a melhor resposta. Leia e confie nos javadocs, não no código. (O código poderia, em princípio, ser diferente para diferentes versões / versões do Java.)
Stephen C
7
@Brandon - Incorreto. Ele só precisa mudar se o comportamento mudar de uma maneira que invalide o javadoc. 1) As chances de isso acontecer para este método são ZERO. Eles não vão fazer uma mudança que justifique uma mudança na especificação, e se eles fizeram, então eles iria mudar o spec. 2) Não invalida meu conselho. Se você ler o javadoc, verá que o comportamento documentado mudou!
Stephen C
2
O método que lança a exceção não seria mais seguro? Normalmente, quando seu código lança uma NullPointerException, é uma coisa boa. Pode não parecer bom para o desenvolvedor no momento ("aww, não, agora preciso voltar e corrigir meu código"), mas desde que o erro foi lançado, você descobriu que precisava corrigir algo. De outra maneira, você está expondo o "nulo" diretamente ao usuário e não está recebendo um erro relatado, a menos que verifique explicitamente um, o que me parece menos seguro.
Tim M.
1
Só para deixar claro, você não pode ligar de verdade String.valueOf(null), isso é um NPE. Funciona apenas para objetos que são nulos.
Noumenon
1
Essa não é a explicação. O String.valueOf(null)realmente resolve a valueOf(char[])sobrecarga. Isso ocorre porque char[]é um tipo mais específico que Object.
Stephen C
17

As diferenças entre String.valueOf (Object) e Object.toString () são:

1) Se a string for nula,

String.valueOf(Object)retornará null, enquanto Object::toString()lançará uma exceção de ponteiro 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) Assinatura:

O método valueOf () da classe String é estático. enquanto o método toString () da classe String não é estático.

A assinatura ou sintaxe do método valueOf () da string é fornecida abaixo:

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)

A assinatura ou sintaxe do toString()método da string é fornecida abaixo:

public String toString()
Shipra Sharma
fonte
13

Em Java, existe alguma diferença entre String.valueOf (Object) e Object.toString ()?

Sim. (E mais ainda, se você considerar sobrecarregar!)

Como o javadoc explica, String.valueOf((Object) null)será tratado como um caso especial pelo valueOfmétodo e o valor "null"será retornado. Por outro lado, null.toString()apenas fornecerá um NPE.

Sobrecarga

Acontece que String.valueOf(null)(note a diferença!) Faz dar um NPE ... apesar do javadoc. A explicação é obscura:

  1. Há várias sobrecargas de String.valueOf, mas há duas que são relevantes aqui: String.valueOf(Object)e String.valueOf(char[]).

  2. Na expressão String.valueOf(null), essas duas sobrecargas são aplicáveis , pois nullé uma atribuição compatível com qualquer tipo de referência.

  3. Quando há duas ou mais sobrecargas aplicáveis , o JLS diz que a sobrecarga para o tipo de argumento mais específico é escolhida.

  4. Como char[]é um subtipo de Object, é mais específico .

  5. Portanto, a String.valueOf(char[])sobrecarga é chamada.

  6. String.valueOf(char[])lança um NPE se seu argumento for uma matriz nula. Ao contrário String.valueOf(Object), não trata nullcomo um caso especial.

(Você pode confirmar isso usando javap -cpara examinar o código de um método que possui uma String.valueOf(null)chamada. Observe a sobrecarga usada na chamada.)

Outro exemplo ilustra a diferença na valueOf(char[])sobrecarga ainda mais claramente:

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

Existe uma convenção de código específica para eles?

Não.

Use o que for mais adequado aos requisitos do contexto em que você o está usando. (Você precisa da formatação para trabalhar null?)

Nota: isso não é uma convenção de código. É apenas programação de senso comum. É mais importante que seu código esteja correto do que seguir algumas convenções estilísticas ou dogmas de "melhores práticas".


Opinião pessoal:

Alguns desenvolvedores adquirem o mau hábito (IMO) de "defender" contra nulos. Então você vê muitos testes para nulos e trata os nulos como casos especiais. A idéia parece impedir que o NPE aconteça.

Acho que é uma má idéia. Em particular, acho que é uma má idéia se o que você faz quando encontra um nullé tentar "fazer o bem" ... sem considerar o porquê de haver um nulllá.

Em geral, é melhor evitar nullestar lá em primeiro lugar ... a menos que isso nulltenha um significado muito específico no seu aplicativo ou no design da API. Portanto, em vez de evitar o NPE com muita codificação defensiva, é melhor deixar o NPE acontecer e, em seguida, rastrear e corrigir a fonte do inesperado nullque acionou o NPE.

Então, como isso se aplica aqui?

Bem, se você pensar bem, usar String.valueOf(obj) pode ser uma maneira de "melhorar". Isso deve ser evitado. Se for inesperado objestar nullno contexto, é melhor usar obj.toString().

Stephen C
fonte
5

A maioria já foi mencionada por outras respostas, mas apenas a adiciono para completar:

  1. As primitivas não têm uma, .toString()pois não são uma implementação da Objectclasse-, portanto, apenasString.valueOf podem ser usadas.
  2. String.valueOftransformará um determinado objeto que é nulla String "null", enquanto .toString()lançará umNullPointerException .
  3. O compilador usará String.valueOfpor padrão quando algo como String s = "" + (...);for usado. É por isso Object t = null; String s = "" + t;que resultará na String "null", e não em um NPE. EDIT: Na verdade, ele vai usar o StringBuilder.append, nãoString.valueOf . Então ignore o que eu disse aqui.

Além desses, aqui está realmente um caso de uso em que String.valueOfe.toString() obtém resultados diferentes:

Digamos que temos um método genérico como este:

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

E nós vamos chamá-lo com um Integertipo como este:Main.<Integer>test() .

Quando criamos uma String, String.valueOfela funciona bem:

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

Isso resultará testem STDOUT.

No .toString()entanto, com um não funcionará:

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

Isso resultará no seguinte erro:

java.lang.ClassCastException: classe java.lang.Stringnão pode ser convertida em classejava.lang.Integer

Experimente online.

Quanto ao porquê, posso me referir a essa pergunta separada e suas respostas . Em suma, no entanto:

  • Ao utilizar .toString()-lo em primeiro lugar reunir e avaliar o objecto, em que o fundido a T(que é uma Stringde Integerfundido neste caso) irá resultar naClassCastException .
  • Ao usá- String.valueOflo, ele verá o genérico Tcomo Objectdurante a compilação e nem se importa com isso Integer. Portanto, ele converterá um Objectpara Object(que o compilador simplesmente ignora). Em seguida, ele será usado String.valueOf(Object), resultando em um Stringcomo esperado. Assim, mesmo que o String.valueOf(Object)vai fazer um .toString()sobre o parâmetro internamente, nós já pulou o elenco e sua tratado como um Object, então temos evitado o ClassCastExceptionque ocorre com o uso de .toString().

Apenas pensei que valia a pena mencionar essa diferença adicional entre String.valueOfe .toString()aqui também.

Kevin Cruijssen
fonte
A última vez que me importei com isso, que teria sido em torno do JDK 1.2, ("" + x)compilado String.valueOf(x), mas qualquer coisa mais complicada usou um StringBuffer(não tínhamos StringBuilderentão).
Neil
4

String.valueOf(Object)e Object.toString()são literalmente a mesma coisa.

Se você der uma olhada na implementação de String.valueOf (Object) , verá que String.valueOf(Object)é basicamente apenas uma invocação com segurança nula detoString() do objeto apropriado:

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
fonte
Não é verdade, use valueOf e toString em uma matriz de caracteres e festeje seus olhos.
Artanis
3

A diferença mais importante é a maneira como eles lidam com referências nulas de String.

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
fonte
1

Quando argumento é null, os String.valueOfretornos "null", mas Object.toStringlança NullPointerException, essa é a única diferença.

Everv0id
fonte
0

Há mais uma grande diferença entre os dois métodos: quando o objeto que estamos convertendo é uma matriz.

Ao converter uma matriz usando Object.toString (), você obtém algum tipo de valor de lixo (@ seguido pelo código de hash da matriz).

Para obter um toString () legível por humanos, você deve usar String.valueOf (char []); Por favor note que este método funciona apenas para Array do tipo char. Eu recomendaria usar Arrays.toString (Object []) para converter matrizes em String.

A segunda diferença é quando o objeto é nulo, ValueOf () retorna uma String "null", enquanto toString () retorna uma exceção de ponteiro nulo.

chintan thakker
fonte
Oi @ Tom, isso é verdade para uma matriz de qualquer tipo. No entanto, se você estiver usando Arrays.toString (Object []), poderá converter uma matriz de qualquer tipo em string.
Thakker Chintan
Oi @ Tom Object.toString () retornando um valor de lixo é verdadeiro para uma matriz de qualquer tipo, você está certo de que String.valueOf (Array) fornecerá uma string correta apenas para uma matriz do tipo char. Eu deveria ter mencionado que, obrigado, vou editá-lo.
você precisa saber é o seguinte
1
Esse não é um valor de lixo, é o nome da classe e o código de hash ( JavaDoc ).
Tom
-1

Não sei dizer exatamente qual é a diferença, mas parece haver uma diferença ao operar no nível de bytes. No cenário de criptografia a seguir, Object.toString () produziu um valor que não pôde ser descriptografado, enquanto String.valueOf () funcionou conforme o esperado ...

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
fonte
Por que falhou? qual é o problema?
Yousha Aleayoub
A explicação é que você está realmente ligando em valueOf(char[])vez de valueOf(Object). O comportamento de valueOf(char[])é significativamente diferente de char[].toString(). De qualquer forma, essa resposta não é adequada, porque você está chamando uma sobrecarga diferente daquela sobre a qual a pergunta é feita.
Stephen C
-2

A seguir, mostra a implementação do java.lang.String.valueOf, conforme descrito na fonte do jdk8u25. Então, de acordo com o meu comentário, não há diferença. Ele chama "Object.toString". Para tipos primitivos, ele o agrupa em sua forma de objeto e chama "toString" nele.

Ver abaixo:

/*
 * 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
fonte