Observei que muitos métodos Java 8 no Oracle JDK usam Objects.requireNonNull()
, que lançam internamente NullPointerException
se o objeto fornecido (argumento) for null
.
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
Mas NullPointerException
será lançado de qualquer maneira se um null
objeto for desreferenciado. Então, por que alguém deveria fazer esse teste nulo extra e jogar
NullPointerException
?
Uma resposta óbvia (ou benefício) é que torna o código mais legível e eu concordo. Estou interessado em conhecer outras razões para usar
Objects.requireNonNull()
no início do método.
java
java-8
nullpointerexception
user4686046
fonte
fonte
Objects.requireNonNull
, seu código não possui ramificação, portanto, uma única passagem em um teste de unidade terá 100% de cobertura :-)Respostas:
Porque você pode tornar as coisas explícitas ao fazer isso. Gostar:
Ou mais curto:
Agora você sabe :
new()
Compare isso com: você cria um objeto Foo hoje e amanhã invoca um método que usa esse campo e lança. Provavelmente, você não saberá amanhã por que essa referência foi nula ontem quando foi passada para o construtor!
Em outras palavras: usando explicitamente esse método para verificar as referências recebidas, você pode controlar o momento em que a exceção será lançada. E na maioria das vezes, você deseja falhar o mais rápido possível !
As principais vantagens são:
bar
não é nulo - e, portanto, você não precisa de nenhumaif (bar == null)
verificação em outros lugares!fonte
this.bar = Objects.requireNonNull(bar, "bar must not be null");
Objects.requireNonNull(bar, "bar must not be null");
. Obrigado por este.this.bar = Objects.requireNonNull(bar, "bar must not be null");
é ok em construtores, mas potencialmente perigosa em outros métodos, se duas ou mais variáveis são definidas no mesmo método. Exemplo: talkwards.com/2018/11/03/…Fail-fast
O código deve falhar o mais rápido possível. Ele não deve executar metade do trabalho e, em seguida, desreferenciar o nulo e travar, deixando apenas metade do trabalho concluído, fazendo com que o sistema esteja em um estado inválido.
Isso geralmente é chamado de "falha antecipada" ou "falha rápida" .
fonte
Isso significa que você detecta o problema imediatamente e de forma confiável .
Considerar:
O .NET melhora isso ao separar
NullReferenceException
("você desferiu um valor nulo") deArgumentNullException
("você não deveria ter passado nulo como argumento - e foi para esse parâmetro). Gostaria que o Java fizesse a mesma coisa, mas mesmo com apenas aNullPointerException
, ainda é muito mais fácil corrigir o código se o erro for gerado no ponto mais inicial em que ele pode ser detectado.fonte
Usar
requireNonNull()
como primeiras instruções em um método permite identificar agora / rapidamente a causa da exceção.O rastreamento de pilha indica claramente que a exceção foi lançada assim que a entrada do método porque o chamador não respeitou os requisitos / contrato. Passar um
null
objeto para outro método pode, de fato, provocar uma exceção por vez, mas a causa do problema pode ser mais complicada de entender, pois a exceção será lançada em uma invocação específica nonull
objeto que pode ser muito mais longe.Aqui está um exemplo concreto e real que mostra por que temos que favorecer a falha rápida em geral e, mais particularmente, usando
Object.requireNonNull()
ou qualquer maneira de executar uma verificação sem nulo nos parâmetros projetados para não sernull
.Suponha que uma
Dictionary
classe que compõe aLookupService
e aList
deString
palavras representativas contidas em. Esses campos foram projetados para não seremnull
e um deles é passado noDictionary
construtor.Agora suponha uma implementação "ruim" de
Dictionary
semnull
verificação na entrada do método (aqui é o construtor):Agora, vamos chamar o
Dictionary
construtor com umanull
referência para owords
parâmetro:A JVM lança o NPE nesta declaração:
A exceção é acionada na
LookupService
classe enquanto a origem dela é bem anterior (oDictionary
construtor). Isso torna a análise geral do problema muito menos óbvia.É
words
null
? Éwords.get(0) null
? Ambos ? Por que um, o outro ou talvez os dois sãonull
? É um erro de codificação noDictionary
(construtor? Método invocado?)? É um erro de codificaçãoLookupService
? (construtor? método invocado?)?Finalmente, teremos que inspecionar mais código para encontrar a origem do erro e, em uma classe mais complexa, talvez até use um depurador para entender mais facilmente o que aconteceu.
Mas por que uma coisa simples (falta de verificação nula) se torna um problema complexo?
Porque permitimos que o bug / falta inicial fosse identificável em um vazamento de componente específico nos componentes inferiores.
Imagine que
LookupService
não era um serviço local, mas um serviço remoto ou uma biblioteca de terceiros com poucas informações de depuração ou imagine que você não tinha 2 camadas, mas 4 ou 5 camadas de invocações de objetos antes denull
serem detectadas? O problema seria ainda mais complexo de analisar.Portanto, a maneira de favorecer é:
Dessa forma, sem dor de cabeça: recebemos a exceção lançada assim que isso é recebido:
Observe que aqui ilustrei o problema com um construtor, mas uma chamada de método pode ter a mesma restrição de verificação não nula.
fonte
Como uma observação lateral, isso falhou rapidamente antes
Object#requireNotNull
foi implementado um pouco diferente do java-9 dentro de algumas das próprias classes jre. Suponha o caso:No java-8 isso compila como (apenas as partes relevantes)
Basicamente, uma operação como:
yourReference.getClass
- que falharia se sua referência fornull
.As coisas mudaram no jdk-9, onde o mesmo código é compilado como
Ou basicamente
Objects.requireNotNull (yourReference)
fonte
O uso básico está verificando e jogando
NullPointerException
imediatamente.Uma alternativa melhor (atalho) para atender ao mesmo requisito é a anotação @NonNull do lombok.
fonte
A exceção de ponteiro nulo é lançada quando você acessa um membro de um objeto que está
null
em um momento posterior.Objects.requireNonNull()
verifica imediatamente o valor e lança a exceção instantaneamente sem avançar.fonte
Eu acho que deve ser usado em construtores de cópia e em alguns outros casos como DI, cujo parâmetro de entrada é um objeto, você deve verificar se o parâmetro é nulo. Em tais circunstâncias, você pode usar esse método estático convenientemente.
fonte
No contexto de extensões de compilador que implementam a verificação de Nullability (por exemplo: uber / NullAway ),
Objects.requireNonNull
deve ser usado com moderação em ocasiões em que você tem um campo anulável que você sabe que não é nulo em um determinado ponto do seu código.Dessa maneira, existem dois usos principais:
Validação
Marcação de anulabilidade (mudando de @Nullable para @Nonnull)
Exemplo de uso da marcação Anulabilidade:
fonte
Além de todas as respostas corretas:
Nós o usamos em fluxos reativos. Geralmente o resultado
NullpointerException
s são agrupados em outras exceções, dependendo da ocorrência no fluxo. Portanto, mais tarde podemos decidir facilmente como lidar com o erro.Apenas um exemplo: imagine que você tem
onde
parseAndValidate
envolve oNullPointerException
derequireNonNull
em umParsingException
.Agora você pode decidir, por exemplo, quando fazer uma nova tentativa ou não:
Sem a verificação, a NullPointerException ocorrerá no diretório
save
método, o que resultará em inúmeras tentativas. Mesmo vale a pena, imagine uma assinatura longa vida, adicionandoAgora o
RetryExhaustException
matará sua assinatura.fonte