Por que int num = Integer.getInteger (“123”) lança NullPointerException?

O código a seguir lança NullPointerException :

 int num = Integer.getInteger("123"); 

Meu compilador está invocando o getInteger em null, já que é estático? Isso não faz nenhum sentido!

O que está acontecendo?

A grande imagem

Há dois problemas em jogo aqui:

  • Integer getInteger(String) não faz o que você acha que faz
    • Ele retorna null neste caso
  • a atribuição de Integer para int causa o auto-unboxing
    • Como o Integer é null , o NullPointerException é lançado

Para analisar (String) "123" para (int) 123 , você pode usar, por exemplo, int Integer.parseInt(String) .

Referências

  • Guia de Linguagem Java / Autoboxing

Referências da API de Integer

  • static int parseInt(String)
  • static Integer getInteger(String)

Em Integer.getInteger

Veja o que a documentação tem a dizer sobre o que esse método faz:

public static Integer getInteger(String nm) : Determina o valor inteiro da propriedade do sistema com o nome especificado. Se não houver nenhuma propriedade com o nome especificado, se o nome especificado estiver vazio ou null , ou se a propriedade não tiver o formato numérico correto, será retornado null .

Em outras palavras, esse método não tem nada a ver com a análise de uma String para um valor int/Integer , mas sim com o método System.getProperty .

É certo que isso pode ser uma surpresa. É lamentável que a biblioteca tenha surpresas como essa, mas ela ensina uma lição valiosa: sempre procure a documentação para confirmar o que um método faz.

Coincidentemente, uma variação deste problema foi apresentada em Return of the Puzzlers: Schock e Awe (TS-5186) , apresentação de JavaOne de 2009 da Sessão Técnica de Josh Bloch e Neal Gafter. Aqui está o slide final:

A moral

  • Métodos estranhos e terríveis se escondem em bibliotecas
    • Alguns têm nomes sonantes inócuos
  • Se o seu código se comportar mal
    • Certifique-se de que você está chamando os methods corretos
    • Leia a documentação da biblioteca
  • Para designers de API
    • Não viole o princípio do menor espanto
    • Não viole a hierarquia de abstração
    • Não use nomes semelhantes para comportamentos totalmente diferentes

Para completar, há também esses methods que são análogos ao Integer.getInteger :

  • Boolean.getBoolean(String)
  • Long.getLong(String)

Perguntas relacionadas

  • Violação Mais Surpreendente do Princípio do Menos Espanto
  • Método mais inadequado / enganoso na API Java Base?

No autounboxing

A outra questão, é claro, é como o NullPointerException é lançado. Para nos concentrarmos nesse problema, podemos simplificar o snippet da seguinte forma:

 Integer someInteger = null; int num = someInteger; // throws NullPointerException!!! 

Aqui está uma citação do Effective Java 2nd Edition, Item 49: Preferir tipos primitivos para primitivos em checkbox:

Em resumo, use primitivos em vez de primitivos em checkbox sempre que tiver a escolha. Tipos primitivos são mais simples e rápidos. Se você deve usar primitivos em checkbox, tenha cuidado! Autoboxing reduz a verbosidade, mas não o perigo, de usar primitivos in a box. Quando seu programa compara duas primitivas em checkbox com o operador == , ele faz uma comparação de identidade, o que quase certamente não é o que você deseja. Quando o seu programa faz cálculos de tipo misto envolvendo primitivas in-box e unboxed, ele faz unboxing e, quando o seu programa faz unboxing, ele pode lançar NullPointerException . Finalmente, quando o seu programa contiver valores primitivos, isso pode resultar em criações de objects dispendiosas e desnecessárias.

Há lugares onde você não tem escolha a não ser usar primitivos em checkbox, por exemplo, genéricos, mas caso contrário, você deve considerar seriamente se a decisão de usar primitivas em checkbox é justificada.

Perguntas relacionadas

  • Qual é a diferença entre um int e um Integer em Java / C #?
  • Por que o autoboxing em Java me permite ter 3 valores possíveis para um booleano?
  • É garantido que o novo Integer (i) == i em Java? (SIM!!!)
  • Ao comparar dois números inteiros no Java, ocorre o desempacotamento automático? (NÃO!!!)
  • Java noob: generics over objects only? (sim Infelizmente)

De http://konigsberg.blogspot.com/2008/04/integergetinteger-are-you-kidding-me.html :

getInteger ‘Determina o valor inteiro da propriedade do sistema com o nome especificado.’

Você quer isso:

 Integer.parseInt("123") 

Por favor, verifique a documentação do método getInteger () . Nesse método, o parâmetro String é uma propriedade do sistema que determina o valor inteiro da propriedade do sistema com o nome especificado. “123” não é o nome de nenhuma propriedade do sistema, como discutido aqui . Se você deseja converter essa String para int , use o método como int num = Integer.parseInt("123") .