Por que String.valueOf (null) lança uma NullPointerException?

127

de acordo com a documentação, o método String.valueOf(Object obj)retorna:

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

Mas como é que quando eu tento fazer isso:

System.out.println("String.valueOf(null) = " + String.valueOf(null));

joga NPE em vez disso? (tente você mesmo se não acredita!)

    Exceção no encadeamento "main" java.lang.NullPointerException
    em java.lang.String. (Fonte desconhecida)
    em java.lang.String.valueOf (fonte desconhecida)

Como isso está acontecendo? A documentação está mentindo para mim? Este é um erro grave em Java?

user282886
fonte

Respostas:

201

O problema é que o String.valueOfmétodo está sobrecarregado :

A Java Specification Language exige que, nesses tipos de casos, a sobrecarga mais específica seja escolhida:

JLS 15.12.2.5 Escolhendo o método mais específico

Se mais de um método membro for acessível e aplicável a uma chamada de método, será necessário escolher um para fornecer o descritor para o envio do método em tempo de execução. A linguagem de programação Java usa a regra de que o método mais específico é escolhido.

Um char[] é um Object , mas nem todos Object é um char[] . Portanto, char[]é mais específico do que Object, e conforme especificado pela linguagem Java, a String.valueOf(char[])sobrecarga é escolhido neste caso.

String.valueOf(char[])espera que o array seja não- nulle, como nullé dado neste caso, ele será lançado NullPointerException.

A "correção" fácil é converter o nullexplicitamente da Objectseguinte maneira:

System.out.println(String.valueOf((Object) null));
// prints "null"

Perguntas relacionadas


Moral da história

Existem vários importantes:

  • Java eficaz 2ª edição, item 41: use sobrecarga criteriosamente
    • Só porque você pode sobrecarregar, não significa que você deveria sempre
    • Eles podem causar confusão (especialmente se os métodos fizerem coisas muito diferentes)
  • Usando um bom IDE, você pode verificar qual sobrecarga está selecionada no momento da compilação
    • Com o Eclipse, você pode passar o mouse sobre a expressão acima e ver que , de fato , a valueOf(char[])sobrecarga está selecionada!
  • Às vezes você deseja transmitir explicitamente null(exemplos a seguir)

Veja também


Na fundição null

Há pelo menos duas situações em que nulla conversão explícita para um tipo de referência específico é necessária:

  • Para selecionar sobrecarga (como fornecido no exemplo acima)
  • Para fornecer nullcomo argumento único um parâmetro vararg

Um exemplo simples deste último é o seguinte:

static void vararg(Object... os) {
    System.out.println(os.length);
}

Então, podemos ter o seguinte:

vararg(null, null, null); // prints "3"
vararg(null, null);       // prints "2"
vararg(null);             // throws NullPointerException!

vararg((Object) null);    // prints "1"

Veja também

Perguntas relacionadas

poligenelubricants
fonte
5
Outra sugestão: Quando você sobrecarrega um método e um argumento pode ser chamado em duas sobrecargas (como nullneste caso), verifique se as duas sobrecargas agem da mesma forma com relação a esse valor!
Joachim Sauer
3
@Joachim: Acabei de ler o item e fiquei agradavelmente surpreso ao descobrir que esses dois métodos foram explicitamente discutidos! Bloch foi um passo além e afirmam que, uma vez String.valueOf(Object)e valueOf(char[])fazer coisas completamente diferentes de qualquer maneira (independentemente da nullou não) que talvez eles não deveriam ter sido sobrecargas em primeiro lugar.
polygenelubricants
Tem uma pergunta ... se você tem um método que retorna um objeto, a instrução return null;seria exatamente a mesma coisa que return (Object) null;?
user972276
17

O problema é que você está ligando String.valueOf(char[])e não String.valueOf(Object) .

A razão para isso é que o Java sempre escolherá a versão mais específica de um método sobrecarregado que funcione com os parâmetros fornecidos. nullé um valor válido para um Objectparâmetro, mas também é um valor válido para um char[]parâmetro.

Para fazer o Java usar a Objectversão, passe nullatravés de uma variável ou especifique uma conversão explícita para Object:

Object o = null;
System.out.println("String.valueOf(null) = " + String.valueOf(o));
// or
System.out.println("String.valueOf(null) = " + String.valueOf((Object) null));
Joachim Sauer
fonte
5

Um bug, numerado 4867608, foi registrado dessa maneira em 2003, que foi resolvido como "não será corrigido" com esta explicação.

Não podemos mudar isso devido a restrições de compatibilidade. Observe que é o método estático público String valueOf (char data []) que acaba sendo chamado e não menciona a substituição de "null" por argumentos nulos.

@ ###. ### 2003-05-23

cbare
fonte
0

Use String.valueOf(null: Any)em Scala.

Profiterole
fonte