O seguinte código gera NullPointerException
:
int num = Integer.getInteger("123");
Meu compilador está invocando getInteger
em null, pois é estático? Isso não faz sentido!
O que está acontecendo?
O seguinte código gera NullPointerException
:
int num = Integer.getInteger("123");
Meu compilador está invocando getInteger
em null, pois é estático? Isso não faz sentido!
O que está acontecendo?
Respostas:
Existem dois problemas em jogo aqui:
Integer getInteger(String)
não faz o que você pensa que faz
null
neste casoInteger
para int
causa o desempacotamento automático
Integer
é null
, NullPointerException
é lançadoPara analisar (String) "123"
a (int) 123
, você pode usar por exemplo int Integer.parseInt(String)
.
Integer
Referências APIInteger.getInteger
Aqui está 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 ounull
, ou se a propriedade não tiver o formato numérico correto,null
será retornado.
Em outras palavras, esse método não tem nada a ver com a análise de a String
para um int/Integer
valor, mas sim com o System.getProperty
método.
É certo que isso pode ser uma grande surpresa. É uma pena que a biblioteca tenha surpresas como essa, mas ela ensina uma lição valiosa: sempre consulte a documentação para confirmar o que um método faz.
Coincidentemente, uma variação desse problema foi apresentada em Return of the Puzzlers: Schlock and Awe (TS-5186) , apresentação de Josh Bloch e Neal Gafter na Sessão Técnica JavaOne 2009. Aqui está o slide de conclusão:
A moral
- Métodos estranhos e terríveis se escondem nas bibliotecas
- Alguns têm nomes que parecem inócuos
- Se o seu código funcionar mal
- Certifique-se de chamar os métodos 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, também existem estes métodos que são análogos a Integer.getInteger
:
A outra questão, claro, é como isso NullPointerException
é jogado. Para focar neste problema, podemos simplificar o snippet da seguinte maneira:
Integer someInteger = null;
int num = someInteger; // throws NullPointerException!!!
Aqui está uma citação do Effective Java 2nd Edition, Item 49: Prefira tipos primitivos a primitivos em caixa:
Em resumo, use primitivos em vez de primitivos encaixotados sempre que você tiver escolha. Os tipos primitivos são mais simples e rápidos. Se você deve usar primitivas em caixa, tome cuidado! O autoboxing reduz a verbosidade, mas não o perigo, de usar primitivas em caixas. Quando seu programa compara duas primitivas em caixa com o
==
operador, ele faz uma comparação de identidade, o que quase certamente não é o que você deseja. Quando seu programa faz cálculos de tipo misto envolvendo primitivos encaixotados e não encaixotados, ele faz o desempacotamento, e quando o seu programa faz o desempacotamento, ele pode lançarNullPointerException
. Finalmente, quando seu programa encaixa valores primitivos, isso pode resultar em criações de objetos caras e desnecessárias.
Há lugares onde você não tem escolha a não ser usar primitivos in a box, por exemplo, genéricos, mas caso contrário, você deve considerar seriamente se a decisão de usar primitivos in a box é justificada.
Integer.getInteger(s)
é mais ou menos equivalente a Integer.parseInt(System.getProperty(s))
? Acho que prefiro o segundo, embora seja mais detalhado, porque destaca o fato de que você está extraindo informações das propriedades do sistema.
Integer.decode
vez de Integer.parseInt
, que procura um líder 0x
ou 0
para analisar o número como hexadecimal ou octal, respectivamente.
NullPointerException
? : programmers.stackexchange.com/questions/158908/…
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")
Verifique a documentação do método getInteger () . Neste método, o String
parâmetro é 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, conforme discutido aqui . Se você deseja converter esta String para int
, use o método como
int num = Integer.parseInt("123")
.