Nenhuma exceção durante a conversão de tipo com um nulo em java

227
String x = (String) null;

Por que não há exceção nesta declaração?

String x = null;
System.out.println(x);

Imprime null. Mas o .toString()método deve lançar uma exceção de ponteiro nulo.

Vicky
fonte
de que exceção você está falando, compilador?
Sajan Chandran 10/09/13

Respostas:

323

Você pode converter nullpara qualquer tipo de referência sem obter nenhuma exceção.

O printlnmétodo não lança ponteiro nulo porque primeiro verifica se o objeto é nulo ou não. Se nulo, simplesmente imprime a string "null". Caso contrário, ele chamará o toStringmétodo desse objeto.

Adicionando mais detalhes: Os métodos de impressão interna chamam o String.valueOf(object)método no objeto de entrada. E, no valueOfmétodo, essa verificação ajuda a evitar a exceção de ponteiro nulo:

return (obj == null) ? "null" : obj.toString();

Para o resto da sua confusão, chamar qualquer método em um objeto nulo deve gerar uma exceção de ponteiro nulo, se não for um caso especial.

Juned Ahsan
fonte
1
@JunedAhsan que casos especiais levariam a não lançar um NPE?
Holloway
@Trengot Verifique uma mencionada na resposta de Peter abaixo.
precisa
144

Você pode converter nullpara qualquer tipo de referência. Você também pode chamar métodos que manipulam a nullcomo argumento, por exemplo System.out.println(Object), mas não pode fazer referência a um nullvalor e chamar um método nele.

BTW Há uma situação complicada em que parece que você pode chamar métodos estáticos em nullvalores.

Thread t = null;
t.yield(); // Calls static method Thread.yield() so this runs fine.
Peter Lawrey
fonte
12
Uau. Se solicitado, eu teria 100% de certeza de que isso lançaria uma exceção. Um caso complicado, de fato.
Magnilex
2
@Magnilex: Absolutamente! essa é uma pergunta típica do truque do exame OCPJP.
Ccpizza 17/03/16
3
Não é porque o compilador no bytecode "otimiza" para t.yield() -> Thread.yeld() assim mesmo? Semelhante a como final int i = 1; while (i == 1)é otimizado parawhile(true)
SGal
@SGal É ainda melhor porque a segunda otimização é AFAIK não obrigatória, enquanto a primeira é.
Paul Stelian
36

Isso é por design. Você pode converter nullpara qualquer tipo de referência. Caso contrário, você não seria capaz de atribuí-lo a variáveis ​​de referência.

André Stannek
fonte
obrigado! Esta observação sobre a atribuição de nulo a variáveis ​​de referência é realmente útil!
Max
22

A conversão de valores nulos é necessária para a construção a seguir, em que um método está sobrecarregado e se nulo é passado para esses métodos sobrecarregados, o compilador não sabe como esclarecer a ambiguidade, portanto, precisamos tipular nulo nesses casos:

class A {
  public void foo(Long l) {
    // do something with l
  }
  public void foo(String s) {
    // do something with s      
  }
}
new A().foo((String)null);
new A().foo((Long)null);

Caso contrário, você não poderá chamar o método necessário.

Mewel
fonte
Na maioria dos casos, a conversão é implícita, por exemplo, String bar = null;lança o nullvalor para String. Até o momento, tive apenas que converter nulo explicitamente em um teste em que um método estava sobrecarregado e queria testar seu comportamento com entrada nula. Ainda assim, é bom saber que eu estava prestes a escrever uma resposta semelhante antes de encontrar a sua.
Vlasec
Curiosidade: l instanceof Longe s instanceof Stringretornará falsenesses casos.
Attila Tanyi
7

Println(Object) usa String.valueOf()

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

Print(String) faz verificação nula.

public void print(String s) {
    if (s == null) {
        s = "null";
    }
    write(s);
}
rocketboy
fonte
5

Muitas respostas aqui já mencionam

Você pode converter nulo para qualquer tipo de referência

e

Se o argumento for nulo, uma sequência igual a "nulo"

Gostaria de saber onde isso é especificado e procurei a especificação Java:

A referência nula sempre pode ser atribuída ou convertida para qualquer tipo de referência (§5.2, §5.3, §5.5).

Se a referência for nula, ela será convertida na cadeia "nula" (quatro caracteres ASCII n, u, l, l).

Arigion
fonte
3

Como outros escreveram, você pode converter nulo para tudo. Normalmente, você não precisa disso, pode escrever:

String nullString = null;

sem colocar o elenco lá.

Mas há ocasiões em que esses elencos fazem sentido:

a) se você deseja garantir que um método específico seja chamado, como:

void foo(String bar) {  ... }
void foo(Object bar) {  ... }

então faria diferença se você digitar

foo((String) null) vs. foo(null)

b) se você pretende usar seu IDE para gerar código; por exemplo, estou escrevendo testes de unidade como:

@Test(expected=NullPointerException.class)
public testCtorWithNullWhatever() {
    new MyClassUnderTest((Whatever) null);
}

Eu estou fazendo TDD; isso significa que a classe "MyClassUnderTest" provavelmente ainda não existe. Ao escrever esse código, posso usar meu IDE para gerar primeiro a nova classe; e, em seguida, gerar um construtor aceitando um argumento "Whatever" "pronto para uso" - o IDE pode descobrir, pelo meu teste, que o construtor deve usar exatamente um argumento do tipo Whatever.

GhostCat
fonte
2

Impressão :

Imprima um objeto. A sequência produzida pelo método String.valueOf (Object) é convertida em bytes

ValorDe :

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

Ele simplesmente retornará uma string com o valor "null" quando o objeto estiver null.

Jeroen Vannevel
fonte
2

Isso é muito útil ao usar um método que seria ambíguo. Por exemplo: JDialog possui construtores com as seguintes assinaturas:

JDialog(Frame, String, boolean, GraphicsConfiguration)
JDialog(Dialog, String, boolean, GraphicsConfiguration)

Preciso usar esse construtor, porque quero definir o GraphicsConfiguration, mas não tenho pai para esse diálogo, portanto, o primeiro argumento deve ser nulo. Usando

JDialog(null, String, boolean, Graphicsconfiguration) 

é ambíguo, portanto, neste caso, posso restringir a chamada convertendo nulo para um dos tipos suportados:

JDialog((Frame) null, String, boolean, GraphicsConfiguration)
Marten Jacobs
fonte
0

Esse recurso de idioma é conveniente nessa situação.

public String getName() {
  return (String) memberHashMap.get("Name");
}

Se memberHashMap.get ("Name") retornar nulo, você ainda desejará que o método acima retorne nulo sem gerar uma exceção. Não importa qual seja a classe, null é null.

Changgull Song
fonte