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?

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


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

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


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.