IllegalArgumentException ou NullPointerException para um parâmetro nulo? [fechadas]

547

Eu tenho um método setter simples para uma propriedade e nullnão é apropriado para essa propriedade em particular. Eu sempre fui rasgado nesta situação: devo jogar um IllegalArgumentException, ou um NullPointerException? Dos javadocs, ambos parecem apropriados. Existe algum tipo de padrão entendido? Ou isso é apenas uma daquelas coisas que você deve fazer o que preferir e as duas coisas estão realmente corretas?

Mike Stone
fonte

Respostas:

299

Parece que um IllegalArgumentExceptioné chamado se você não quiser nullser um valor permitido e o NullPointerExceptionseria lançado se você estivesse tentando usar uma variável que acaba sendo null.

Greg Hurlman
fonte
33
As seguintes respostas a esta pergunta apresentam argumentos convincentes de que NullPointerException é a exceção correta: stackoverflow.com/a/8160/372926 ; stackoverflow.com/a/8196334/372926 ; e stackoverflow.com/a/6358/372926 .
SamStephens
2
IllegalArgumentExceptionestá em contradição com o Java Objects.requireNonNull (T) e da goiaba Preconditions.checkNotNull (T) que joga um NullPointerException. No entanto, a resposta certa é definitivamente IllegalArgumentException explicada na excelente resposta de Jason Cohen e na seção de comentários .
Matoni
417

Você deve usar IllegalArgumentException(IAE), não NullPointerException(NPE) pelos seguintes motivos:

Primeiro, o NPE JavaDoc lista explicitamente os casos em que o NPE é apropriado. Observe que todos eles são lançados pelo tempo de execução quando nullusados ​​inadequadamente. Por outro lado, o IAE JavaDoc não poderia ser mais claro: "Lançado para indicar que um método recebeu um argumento ilegal ou inapropriado". Sim, é você!

Segundo, quando você vê um NPE em um rastreamento de pilha, o que você assume? Provavelmente alguém desreferenciou a null. Quando você vê o IAE, assume que o responsável pela chamada do método na parte superior da pilha passou com um valor ilegal. Novamente, a última suposição é verdadeira, a primeira é enganosa.

Terceiro, como o IAE foi claramente projetado para validar parâmetros, você deve assumi-lo como a opção padrão de exceção. Então, por que você escolheria o NPE? Certamente não é para um comportamento diferente - você realmente espera que o código de chamada pegue os NPE separadamente do IAE e faça algo diferente como resultado? Você está tentando comunicar uma mensagem de erro mais específica? Mas você pode fazer isso no texto da mensagem de exceção de qualquer maneira, como faria com todos os outros parâmetros incorretos.

Quarto, todos os outros dados de parâmetros incorretos serão IAE; então, por que não ser consistente? Por que um ilegal nullé tão especial que merece uma exceção separada de todos os outros tipos de argumentos ilegais?

Por fim, aceito o argumento fornecido por outras respostas de que partes da API Java usam o NPE dessa maneira. No entanto, a API Java é inconsistente com tudo, desde tipos de exceção a convenções de nomenclatura, então acho que apenas copiar cegamente (sua parte favorita) a API Java não é um argumento suficientemente bom para superar essas outras considerações.

Jason Cohen
fonte
120
Java 2nd Edition efetivo, item 60: "Indiscutivelmente, todas as invocações errôneas de métodos se resumem a um argumento ou estado ilegal, mas outras exceções são usadas de maneira padrão para certos tipos de argumentos e estados ilegais. Se um chamador passa nulo em algum parâmetro para o qual valores nulos são proibidos, a convenção determina que NullPointerException seja lançada em vez de IllegalArgumentException. Da mesma forma, se um chamador passa um valor fora do intervalo em um parâmetro que representa um índice em uma sequência, IndexOutOfBoundsException deve ser lançada em vez de IllegalArgumentException. "
Gili
33
O JavaDoc para NPE também declara o seguinte: "Os aplicativos devem lançar instâncias dessa classe para indicar outros usos ilegais do objeto nulo". Este poderia ser mais claro :(
R. Martinho Fernandes
12
Infelizmente, os métodos de validação Validate.notNull(commons lang) e Preconditions.checkNotNull(goiaba), ambos do throw NPE :-(
Aaron Digulla
2
Embora Goiaba também tem Preconditions.checkArgument () throws IllegalArgumentException ...
michaelok
16
@AaronDigulla, da documentação do Guava: "Percebemos que existem muitos argumentos válidos a favor de lançar o IAE em um argumento nulo. Na verdade, se tivéssemos uma máquina do tempo para voltar> 15 anos, talvez tentássemos pressionar as coisas. No entanto, decidimos manter a preferência JDK e Effective Java de NullPointerException. Se você acredita firmemente que o IAE está certo, você ainda o tem checkArgument(arg != null), apenas sem a conveniência de retornar o argumento, ou pode criar um utilitário local para o seu projeto. " code.google.com/p/guava-libraries/wiki/IdeaGraveyard
Arto Bendiken
162

O padrão é jogar o NullPointerException. O geralmente infalível "Java Efetivo" discute isso brevemente no Item 42 (primeira edição), Item 60 (segunda edição) ou Item 72 (terceira edição) "Favorecer o uso de exceções padrão":

"Pode-se argumentar que todas as invocações errôneas de métodos se resumem a argumentos ou estados ilegais, mas outras exceções são usadas de maneira padrão para certos tipos de argumentos e estados ilegais. Se um chamador passa nulo em algum parâmetro para o qual valores nulos são proibidos, a convenção determina que NullPointerException será lançado em vez de IllegalArgumentException. "

GaryF
fonte
95
Eu discordo fortemente. NullPointerExceptions só deve ser lançado se a JVM seguir acidentalmente uma referência nula. Essa é a diferença que ajuda você quando chamado para examinar o código às 3 da manhã.
Thorbjørn Ravn Andersen
26
Eu não necessariamente concordo com o padrão (eu poderia realmente ir de qualquer maneira sobre o assunto), mas é ISSO o que o uso padrão em todo o JDK é, portanto, o Java eficaz defende isso. Penso que este é um caso de escolher se segue ou não o padrão ou se faz o que acha certo. A menos que você tenha um bom motivo (e isso certamente possa se qualificar), é melhor seguir a prática padrão.
28410 GaryF
21
O rastreamento da exceção mostra o ponto da exceção; portanto, se a diferença no tipo da exceção lhe causa um inferno ou é "a diferença que ajuda você", você está fazendo algo muito errado.
Jim Balter
8
Fantasias e sofismas. Logo abaixo, MB escreve "Observe que os argumentos sobre depuração rígida são falsos porque é claro que você pode enviar uma mensagem para NullPointerException dizendo o que era nulo e por que não deveria ser nulo. Assim como em IllegalArgumentException."
Jim Balter
10
Como resposta original aqui, deixe-me dizer que isso não importa muito. Certamente não garante 6 anos de conversa. Escolha um, como quiser e seja consistente. O padrão, como apontei, é o NPE. Se você preferir o IAE por qualquer motivo, faça-o. Apenas seja consistente.
GaryF
138

Eu era a favor de jogar IllegalArgumentExceptionparâmetros nulos, até hoje, quando notei o java.util.Objects.requireNonNullmétodo em Java 7. Com esse método, em vez de fazer:

if (param == null) {
    throw new IllegalArgumentException("param cannot be null.");
}

você pode fazer:

Objects.requireNonNull(param);

e lançará um NullPointerExceptionse o parâmetro que você passar for null.

Dado que esse método está bem no meio java.util, considero sua existência uma indicação bastante forte de que jogar NullPointerExceptioné "a maneira Java de fazer as coisas".

Eu acho que sou decidido de qualquer forma.

Observe que os argumentos sobre depuração rígida são falsos, porque é claro que você pode fornecer uma mensagem NullPointerExceptiondizendo o que era nulo e por que não deveria ser nulo. Assim como com IllegalArgumentException.

Uma vantagem adicional NullPointerExceptioné que, em código crítico de alto desempenho, você pode dispensar uma verificação explícita de nulo (e uma NullPointerExceptioncom uma mensagem de erro amigável) e confiar apenas no NullPointerExceptionque você obterá automaticamente quando chamar um método no nulo parâmetro. Desde que você chame um método rapidamente (ou seja, falhe rapidamente), você terá essencialmente o mesmo efeito, mas não tão amigável para o desenvolvedor. Na maioria das vezes, provavelmente é melhor verificar explicitamente e enviar com uma mensagem útil para indicar qual parâmetro foi nulo, mas é bom ter a opção de alterar isso se o desempenho exigir, sem violar o contrato publicado do método / construtor.

MB.
fonte
14
A goiaba Preconditions.checkNotNull(arg)também lança NPE.
Assylias 14/10/12
14
Isso realmente não está adicionando mais peso ao NullPointerException para ARGUMENTS nulos ilegais. O JDK requireNonNull () e Guava checkNotNull () podem ser chamados em qualquer lugar do código, com qualquer objeto. Você pode chamá-los dentro de um loop, por exemplo. requireNotNull () e checkNotNull () não poderiam assumir como invocados com alguns argumentos de método e lançam IllegalArgumentException. Observe que o Guava também possui Preconditions.checkArgument (), que lança IllegalArgumentException.
Bogdan Calmac 8/03/13
2
Um ponto justo de Bogdan, embora eu suspeite que o uso típico (e geralmente pretendido) de requireNonNull seja para verificação de argumentos. Se você precisasse verificar se algo não estava nulo em um loop, eu teria pensado que uma afirmação seria a maneira típica.
MB.
15
Eu acho que o JavaDoc de Object.requireNonNull () adiciona peso ao argumento: "Este método é projetado principalmente para realizar validação de parâmetros em métodos e construtores"
Richard Zschech
Lembre-se de que o argumento de desempenho em favor de verificações nulas implícitas geralmente é inválido. O JIT é capaz de reconhecer verificações nulas do usuário e excluir a verificação nula implícita a seguir, e / ou usar o mesmo conjunto de otimizações em qualquer tipo de verificação nula. Consulte este wiki para obter mais informações, em particular: Verificações nulas escritas pelo usuário são, na maioria dos casos, funcionalmente idênticas às inseridas pela JVM. Obviamente, se você estiver fazendo algo mais sofisticado em suas mensagens nulas, como as personalizadas, essa otimização poderá não se aplicar.
BeeOnRope
70

Costumo seguir o design das bibliotecas JDK, especialmente Coleções e Concorrência (Joshua Bloch, Doug Lea, esses caras sabem como criar APIs sólidas). De qualquer forma, muitas APIs no JDK lançam proativamente NullPointerException.

Por exemplo, o Javadoc para Map.containsKeyestados:

@throws NullPointerException se a chave for nula e este mapa não permitir chaves nulas (opcional).

É perfeitamente válido lançar seu próprio NPE. A convenção é incluir o nome do parâmetro que foi nulo na mensagem da exceção.

O padrão é:

public void someMethod(Object mustNotBeNull) {  
    if (mustNotBeNull == null) {  
        throw new NullPointerException("mustNotBeNull must not be null");  
    }  
}

Faça o que fizer, não permita que um valor ruim seja definido e lance uma exceção mais tarde quando outro código tentar usá-lo. Isso torna a depuração um pesadelo. Você deve sempre seguir o princípio "fail-fast".

Mark Renouf
fonte
3
Alimento para reflexão: Talvez o motivo pelo qual NullPointerException não estenda o IllegalArgumentException seja que o primeiro possa ocorrer em casos que não envolvam argumentos de método.
Gili
2
@ Gili: talvez esse problema exista, em primeiro lugar, porque Java não suporta herança múltipla. Se o Java suportar MI, você poderá lançar uma exceção herdada de IllegalArgumentException e NullPointerException.
Lie Ryan
7
A mensagem não precisa incluir o argumento, pois seria sempre nulo, fornecendo: "nulo não deve ser nulo", não muito útil. :-) Caso contrário, eu concordo, você pode criar um NPE "rico", com uma mensagem significativa.
PhiLho 22/07
5
Eu tenho que concordar - siga a API padrão em caso de dúvida. Nem tudo na API é ideal, mas ainda é mantido e iterado por centenas de desenvolvedores e usado por milhões de programadores. Agora, no Java 7, temos outro exemplo do NPE sendo usado dessa maneira; o método Objects.requireNonNull (T obj) - claramente especificado para verificar se as referências a objetos são não nulas, claramente especificado para validação de parâmetros em métodos / construtores e claramente especificado para gerar um NPE se o objeto for nulo. Fim de
flamming_python 30/06
44

Votou o argumento de Jason Cohen porque foi bem apresentado. Deixe-me desmembrá-lo passo a passo. ;-)

  • O NPE JavaDoc diz explicitamente "outros usos ilegais do objeto nulo" . Se fosse limitado apenas a situações em que o tempo de execução encontrasse um nulo quando não deveria, todos esses casos poderiam ser definidos de maneira muito mais sucinta.

  • Não é possível evitá-lo se você assumir a coisa errada, mas assumindo que o encapsulamento foi aplicado corretamente, você realmente não deve se importar ou perceber se um nulo foi desreferenciado de forma inadequada versus se um método detectou um nulo inadequado e acionou uma exceção.

  • Eu escolheria o NPE ao invés do IAE por várias razões

    • É mais específico sobre a natureza da operação ilegal
    • A lógica que permite valores nulos por engano tende a ser muito diferente da lógica que permite valores ilegais por engano. Por exemplo, se estou validando dados inseridos por um usuário, se obtiver um valor inaceitável, a origem desse erro será com o usuário final do aplicativo. Se eu receber um valor nulo, isso é erro do programador.
    • Valores inválidos podem causar coisas como estouros de pilha, erros de falta de memória, exceções de análise etc. Na verdade, a maioria dos erros geralmente se apresenta, em algum momento, como um valor inválido em alguma chamada de método. Por esse motivo, vejo o IAE como realmente o MAIS GERAL de todas as exceções em RuntimeException.
  • Na verdade, outros argumentos inválidos podem resultar em todos os tipos de outras exceções. UnknownHostException , FileNotFoundException , uma variedade de exceções de erro de sintaxe, IndexOutOfBoundsException , falhas de autenticação, etc., etc.

Em geral, acho que o NPE é muito difamado, porque tradicionalmente tem sido associado a códigos que não seguem o princípio de falha rápida . Isso, além da falha do JDK em preencher os NPEs com uma sequência de mensagens, realmente criou um forte sentimento negativo que não é bem fundamentado. De fato, a diferença entre NPE e IAE da perspectiva do tempo de execução é estritamente o nome. Dessa perspectiva, quanto mais preciso você for o nome, mais clareza você dará ao chamador.

Christopher Smith
fonte
A diferença entre a maioria das exceções não verificadas é apenas o nome.
Thorbjørn Ravn Andersen
20

É uma questão de estilo "Guerra Santa". Em outras palavras, ambas as alternativas são boas, mas as pessoas terão suas preferências que defenderão até a morte.

Steve McLeod
fonte
Não, existe apenas uma resposta certa para essa pergunta e é usar a exceção Throw IllegalArgument quando a entrada do método estiver incorreta. Também em dev ambiente, você pode usar afirmações para verificar a validade de entrada e jogar exceção adequada;)
Mr.Q
@ Mr.Q E eu acho que NullPointerExceptiondeve ser jogado: é a convenção de que os usos do JDK, e requer para interfaces, é mais específico (como IndexOutOfBoundsException, etc.), etc.
Solomon Ucko
kekekekkek ...: D
Yousha Aleayoub
17

Se é um settermétodo e nullestá sendo passado para ele, acho que faria mais sentido lançar um IllegalArgumentException. A NullPointerExceptionparece fazer mais sentido no caso em que você está tentando realmente usar o null.

Então, se você estiver usando-lo e é null, NullPointer. Se ele está sendo passado e é null, IllegalArgument.

Jeremy Privett
fonte
9

O Apache Commons Lang tem uma NullArgumentException que executa várias das coisas discutidas aqui: estende IllegalArgumentException e seu único construtor leva o nome do argumento que deveria ter sido não nulo.

Embora eu ache que jogar algo como uma NullArgumentException ou IllegalArgumentException descreva com mais precisão as circunstâncias excepcionais, meus colegas e eu optamos por adiar os conselhos de Bloch sobre o assunto.

Brian T. Grant
fonte
7
Observe que removeu do commons-lang3: apache-commons.680414.n4.nabble.com/...
artbristol
7

Não poderia concordar mais com o que está sendo dito. Falhe cedo, falhe rápido. Muito bom mantra de exceção.

A pergunta sobre qual exceção lançar é principalmente uma questão de gosto pessoal. Na minha opinião, IllegalArgumentException parece mais específico do que usar um NPE, pois está me dizendo que o problema foi com um argumento que eu passei para o método e não com um valor que pode ter sido gerado durante a execução do método.

Meus 2 centavos

Allain Lalonde
fonte
7

Na verdade, a questão de lançar IllegalArgumentException ou NullPointerException é, na minha humilde visão, apenas uma "guerra santa" para uma minoria com um entendimento incomodo do tratamento de exceções em Java. Em geral, as regras são simples e da seguinte maneira:

  • violações de restrição de argumento devem ser indicadas o mais rápido possível (-> falha rápida), a fim de evitar estados ilegais que são muito mais difíceis de depurar
  • no caso de um ponteiro nulo inválido por qualquer motivo, lance NullPointerException
  • no caso de um índice ilegal de matriz / coleção, jogue ArrayIndexOutOfBounds
  • no caso de um tamanho negativo de matriz / coleção, lance NegativeArraySizeException
  • no caso de um argumento ilegal que não seja coberto pelo descrito acima e para o qual você não tenha outro tipo de exceção mais específico, jogue IllegalArgumentException como uma cesta de lixo
  • por outro lado, no caso de uma violação de restrição DENTRO DE UM CAMPO que não pôde ser evitada por falha rápida por algum motivo válido, capture e repita como IllegalStateException ou uma exceção verificada mais específica. Nunca deixe passar o NullPointerException original, ArrayIndexOutOfBounds, etc, neste caso!

Há pelo menos três razões muito boas contra o caso de mapear todos os tipos de violações de restrição de argumento para IllegalArgumentException, com a terceira provavelmente sendo tão severa a ponto de marcar o estilo inadequado da prática:

(1) Um programador não pode assumir com segurança que todos os casos de violações de restrição de argumento resultam em IllegalArgumentException, porque a grande maioria das classes padrão usa essa exceção em vez de uma cesta de lixo, se não houver um tipo mais específico de exceção disponível. Tentar mapear todos os casos de violações de restrição de argumento para IllegalArgumentException em sua API apenas leva à frustração do programador usando suas classes, pois as bibliotecas padrão geralmente seguem regras diferentes que violam as suas e a maioria dos usuários da API também as usa!

(2) O mapeamento das exceções realmente resulta em um tipo diferente de anomalia, causada por herança única: todas as exceções Java são classes e, portanto, suportam apenas herança única. Portanto, não há como criar uma exceção que seja realmente uma NullPointerException e uma IllegalArgumentException, pois as subclasses só podem herdar de uma ou de outra. Lançar uma IllegalArgumentException no caso de um argumento nulo torna mais difícil para os usuários da API distinguir entre problemas sempre que um programa tenta corrigir programaticamente o problema, por exemplo, alimentando valores padrão em uma repetição de chamada!

(3) O mapeamento realmente cria o perigo de mascarar erros: para mapear violações de restrição de argumento em IllegalArgumentException, você precisará codificar uma tentativa externa de captura dentro de cada método que possua argumentos restritos. No entanto, simplesmente capturar RuntimeException nesse bloco de captura está fora de questão, porque esse risco corre o mapeamento de RuntimeExceptions documentados lançados pelos métodos de libery usados ​​dentro do seu em IllegalArgumentException, mesmo que eles não sejam causados ​​por violações de restrição de argumento. Portanto, você precisa ser muito específico, mas mesmo esse esforço não o protege do caso de mapear acidentalmente uma exceção de tempo de execução não documentada de outra API (ou seja, um bug) em uma IllegalArgumentException da sua API.

Por outro lado, com a prática padrão, as regras permanecem simples e as causas de exceção permanecem desmascaradas e específicas. Para o responsável pela chamada do método, as regras também são fáceis: - se você encontrar uma exceção de tempo de execução documentada de qualquer tipo porque passou um valor ilegal, repita a chamada com um padrão (pois essas exceções específicas são necessárias) ou corrija seu código - se, por outro lado, você encontrar uma exceção de tempo de execução que não está documentada para um determinado conjunto de argumentos, envie um relatório de bug aos criadores do método para garantir que seu código ou sua documentação seja corrigida.

Sascha Baumeister
fonte
6

A prática aceita se você usar a IllegalArgumentException (String message) para declarar um parâmetro inválido e fornecer o máximo de detalhes possível ... Por assim dizer, um parâmetro foi considerado nulo enquanto a exceção não nula, você faria algo como isso:

if( variable == null )
    throw new IllegalArgumentException("The object 'variable' cannot be null");

Você não tem praticamente nenhum motivo para usar implicitamente a "NullPointerException". O NullPointerException é uma exceção lançada pela Java Virtual Machine quando você tenta executar o código na referência nula (como toString () ).

Claude Houle
fonte
6

Lançando uma exceção exclusiva para null argumentos (seja NullPointerExceptionum tipo personalizado) torna o nullteste automatizado mais confiável. Esse teste automatizado pode ser feito com reflexão e um conjunto de valores predefinidos, como em goiaba s' NullPointerTester. Por exemplo, NullPointerTestertentaria chamar o seguinte método ...

Foo(String string, List<?> list) {
  checkArgument(string.length() > 0);
  // missing null check for list!
  this.string = string;
  this.list = list;
}

... com duas listas de argumentos: "", nulle null, ImmutableList.of(). Testaria se cada uma dessas chamadas gera o esperado NullPointerException. Para esta implementação, passar uma nulllista não produz NullPointerException. No entanto, produz um IllegalArgumentExceptionporque NullPointerTesterusa uma sequência padrão de "". E seNullPointerTester espera apenas NullPointerExceptionpara nullvalores, ele pega o bug. Se espera IllegalArgumentException, perde.

Chris Povirk
fonte
5

Algumas coleções assumem que nullé rejeitado usando em NullPointerExceptionvez de IllegalArgumentException. Por exemplo, se você comparar um conjunto que contém nullum conjunto que rejeita null, o primeiro conjunto chama containsAllo outro e captura seu NullPointerException- mas não IllegalArgumentException. (Estou olhando para a implementação deAbstractSet.equals .)

Você poderia argumentar razoavelmente que o uso de exceções não verificadas dessa maneira é um antipadrão, que comparar coleções que contêm nullcom coleções que não podem conter nullé um bug provável que realmente deve gerar uma exceção ou que a criação nullde uma coleção é uma má ideia. . No entanto, a menos que você esteja disposto a dizer que isso equalsdeve gerar uma exceção nesse caso, você ficará paralisado ao lembrar que NullPointerExceptioné necessário em determinadas circunstâncias, mas não em outras. ("IAE antes do NPE, exceto depois de 'c' ...")

Chris Povirk
fonte
Não vejo como o contém lança um NPE, dependendo de um elemento dentro da coleção. O único motivo pelo qual um NPE é lançado (em conflito) é se a coleção em si for nula (nesse caso, o NPE é lançado porque tenta acessar seu iterador). No entanto, isso levanta a questão se a entrada nula deve ser verificada ou se deve propagar até que tente acessar.
Alowaniak
2
new TreeSet<>().containsAll(Arrays.asList((Object) null));joga NPEporque o Listcontém null.
22820 Chris Povirk
1
Ah, de fato, o TreeSet # contém throws NPE "se o elemento especificado for nulo e esse conjunto usar ordem natural ou seu comparador não permitir elementos nulos". Só olhou para AbstractSet que permite nulo, meu mal. Pessoalmente, acho estranho que ele não retorne apenas falso, pois nesse caso não é possível adicionar um nulo.
Alowaniak 12/07
5

Como uma questão subjetiva, isso deve ser fechado, mas como ainda está aberto:

Isso faz parte da política interna usada no meu local de trabalho anterior e funcionou muito bem. Isso tudo é da memória, então não consigo me lembrar da letra exata. Vale ressaltar que eles não usaram exceções verificadas, mas isso está além do escopo da pergunta. As exceções não verificadas que eles usaram caíram em 3 categorias principais.

NullPointerException: não atire intencionalmente. Os NPEs devem ser lançados apenas pela VM ao remover uma referência nula. Todo esforço possível deve ser feito para garantir que eles nunca sejam lançados. @Nullable e @NotNull devem ser usados ​​em conjunto com as ferramentas de análise de código para encontrar esses erros.

IllegalArgumentException: lançado quando um argumento para uma função não está em conformidade com a documentação pública, de modo que o erro possa ser identificado e descrito em termos dos argumentos passados. A situação do OP se enquadra nessa categoria.

IllegalStateException: Lançada quando uma função é chamada e seus argumentos são inesperados no momento em que são passados ​​ou incompatíveis com o estado do objeto do qual o método é membro.

Por exemplo, havia duas versões internas da IndexOutOfBoundsException usadas em itens que tinham um comprimento. Uma subclasse de IllegalStateException, usada se o índice for maior que o comprimento. A outra, uma subclasse de IllegalArgumentException, usada se o índice for negativo. Isso ocorreu porque você poderia adicionar mais itens ao objeto e o argumento seria válido, enquanto um número negativo nunca é válido.

Como eu disse, esse sistema funciona muito bem e foi preciso alguém para explicar por que a distinção existe: "Dependendo do tipo de erro, é bastante simples você descobrir o que fazer. Mesmo que você não consiga realmente descobrir Para descobrir o que deu errado, você pode descobrir onde detectar esse erro e criar informações adicionais de depuração ".

NullPointerException: manipule o caso Null ou insira uma asserção para que o NPE não seja lançado. Se você colocar uma afirmação, é apenas um dos outros dois tipos. Se possível, continue a depuração como se a afirmação estivesse lá em primeiro lugar.

IllegalArgumentException: você tem algo errado no site de chamadas. Se os valores transmitidos forem de outra função, descubra por que você está recebendo um valor incorreto. Se você estiver passando um de seus argumentos, propague o erro verifica a pilha de chamadas até encontrar a função que não está retornando o que você espera.

IllegalStateException: você não chamou suas funções na ordem correta. Se você estiver usando um de seus argumentos, verifique-os e gere uma IllegalArgumentException descrevendo o problema. Você pode propagar as bochechas contra a pilha até encontrar o problema.

De qualquer forma, o argumento dele era que você só pode copiar o IllegalArgumentAssertions na pilha. Não há como você propagar IllegalStateExceptions ou NullPointerExceptions na pilha porque eles têm algo a ver com a sua função.

Ben Seidel
fonte
4

Em geral, um desenvolvedor nunca deve lançar uma NullPointerException. Essa exceção é lançada pelo tempo de execução quando o código tenta desreferenciar uma variável cujo valor é nulo. Portanto, se o seu método deseja proibir explicitamente nulo, em vez de apenas um valor nulo aumentar uma NullPointerException, você deve lançar uma IllegalArgumentException.


fonte
9
O JavaDoc no NPE tem outra opinião: "Os aplicativos devem lançar instâncias dessa classe para indicar outros usos ilegais do objeto nulo.". Não seja tão categórica
Dönz
4

Queria destacar argumentos nulos de outros argumentos ilegais; portanto, derivei uma exceção do IAE chamada NullArgumentException. Mesmo sem precisar ler a mensagem de exceção, sei que um argumento nulo foi passado para um método e, lendo a mensagem, descubro qual argumento foi nulo. Eu ainda pego o NullArgumentException com um manipulador IAE, mas nos meus logs é onde posso ver a diferença rapidamente.

Jason Fritcher
fonte
Adotei a abordagem "lançar nova IllegalArgumentException (" foo == null ")". Você precisa fazer login o nome da variável de qualquer maneira (para ter certeza de que você está olhando para a direita sttatement etc)
Thorbjørn Ravn Andersen
4

a dicotomia ... Eles não se sobrepõem? Somente partes não sobrepostas de um todo podem fazer uma dicotomia. Da maneira que eu vejo:

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));
Luis Daniel Mesa Velasquez
fonte
1
Isso dobraria a sobrecarga para a criação de exceções e não ajudaria, pois a captura NullPointerExceptionnão faria nada. A única coisa que poderia ajudar é IllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerException, mas não temos herança múltipla.
Maaartinus
Eu acredito que exceções mais específicas devem ser envoltas por exceções mais gerais. NPE é para uma expressão enquanto IAE é para um método. Como os métodos contêm instruções que contêm expressões, o IAE é mais geral.
precisa saber é o seguinte
Em relação às despesas gerais, não faço ideia. Mas como os rastreamentos de pilha seriam basicamente idênticos, exceto que o nome da exceção foi alterado no meio, acho que não deve haver muita sobrecarga para exceções duplas. Se alguém estiver preocupado com a sobrecarga, ele poderá usar as instruções "if" para retornar um valor nulo ou -1 em vez de lançar uma exceção.
precisa saber é o seguinte
4

NullPointerExceptionlançada ao tentar acessar um objeto com uma variável de referência cujo valor atual é null.

IllegalArgumentException lançado quando um método recebe um argumento formatado de forma diferente do que o método espera.

Nitesh Soomani
fonte
3

De acordo com o seu cenário, IllegalArgumentExceptioné a melhor escolha, porque nullnão é um valor válido para sua propriedade.

leo
fonte
0

Idealmente, as exceções de tempo de execução não devem ser lançadas. Uma exceção marcada (exceção comercial) deve ser criada para o seu cenário. Como se qualquer uma dessas exceções for lançada e registrada, ela desviará o desenvolvedor ao passar pelos logs. Em vez disso, as exceções de negócios não criam esse pânico e geralmente são ignoradas durante a solução de problemas dos logs.

vijay
fonte
-1

As definições dos links para as duas exceções acima são IllegalArgumentException: Lançadas para indicar que um método recebeu um argumento ilegal ou inapropriado. NullPointerException: Lançado quando um aplicativo tenta usar null em um caso em que um objeto é necessário.

A grande diferença aqui é que o IllegalArgumentException deve ser usado ao verificar se um argumento para um método é válido. NullPointerException deve ser usado sempre que um objeto está sendo "usado" quando é nulo.

Espero que ajude a colocar os dois em perspectiva.

martinatime
fonte
1
O ponto mais importante é que é o aplicativo que está usando nulo, não o tempo de execução. Portanto, há uma sobreposição bastante grande entre "quando um método recebe um argumento ilegal ou inadequado" e "quando um aplicativo está usando nulo". Em teoria, se um aplicativo passar um nulo para um campo que requer não nulo, os dois critérios serão atendidos.
Christopher Smith
-1

Se for um "setter", ou em algum lugar em que eu vou conseguir que um membro use mais tarde, costumo usar IllegalArgumentException.

Se for algo que eu vou usar (desreferencia) agora no método, eu lanço um NullPointerException proativamente. Eu gosto mais disso do que deixar o tempo de execução fazê-lo, porque posso fornecer uma mensagem útil (parece que o tempo de execução também pode fazer isso, mas isso é um discurso retórico por mais um dia).

Se estou substituindo um método, utilizo o que o método substituído usar.

erickson
fonte
-1

Você deve lançar uma IllegalArgumentException, pois tornará óbvio para o programador que ele fez algo inválido. Os desenvolvedores estão tão acostumados a ver o NPE lançado pela VM, que qualquer programador não perceberia imediatamente seu erro e começaria a procurar aleatoriamente, ou pior, culpar seu código por ser 'buggy'.

Will Sargent
fonte
4
Desculpe, se um programador olhar ao redor "aleatoriamente" ao receber qualquer tipo de exceção ... alterar o nome de uma exceção não ajudará muito.
Christopher Smith
-1

Nesse caso, IllegalArgumentException transmite informações claras ao usuário usando sua API que "não deve ser nulo". Como outros usuários do fórum apontaram, você pode usar o NPE se desejar transmitir as informações corretas ao usuário usando sua API.

GaryF e tweakt eliminaram as referências "Effective Java" (pelo que juro) que recomendam o uso do NPE. E observar como outras boas APIs são construídas é a melhor maneira de ver como construir sua API.

Outro bom exemplo é examinar as APIs do Spring. Por exemplo, org.springframework.beans.BeanUtils.instantiateClass (construtor ctor, Object [] args) possui uma linha Assert.notNull (ctor, "O construtor não deve ser nulo"). O método org.springframework.util.Assert.notNull (objeto Objeto, mensagem String) verifica se o argumento (objeto) passado é nulo e, se for, lança uma nova IllegalArgumentException (mensagem) que é capturada na organização. método springframework.beans.BeanUtils.instantiateClass (...).


fonte
-5

Se você optar por lançar um NPE e estiver usando o argumento em seu método, pode ser redundante e caro verificar explicitamente se existe um nulo. Eu acho que a VM já faz isso por você.

jassuncao
fonte
O tempo de execução não incluirá uma mensagem significativa.
mP.
Na verdade, esse comentário pode derivar alguma outra opinião. Deixe a VM falar NPEainda; os programadores falam IAEantes da VM, se quiserem.
Jin Kwon
1
Caro? Eu não acho que == nulo seja tão caro ... Além disso, o argumento nulo pode ser armazenado apenas para uso posterior e lançará uma exceção muito tempo após a chamada do método, dificultando o rastreamento do erro. Ou você pode criar um objeto caro antes de usar o argumento nulo e assim por diante. A detecção precoce parece ser uma boa opção.
PhiLho
O voto negativo desta resposta é um mal-entendido do hardware por trás. Certamente, as verificações de hardware (que a CPU faz) são mais baratas que a verificação explícita. A desreferenciação de null é um caso especial SegmentationFault (SegV) (acesso a uma página não pertencente ao processo) que a CPU / OS verifica e o JRE manipula como um caso especial que lança NullPointerException.
digital_infinity