Pergunta

Eu sou de um fundo .NET e agora intrometendo em Java.

Atualmente, estou tendo grandes problemas projetando uma API defensivamente contra entrada defeituoso. Vamos dizer que eu tenho o código seguinte (perto o suficiente):

public void setTokens(Node node, int newTokens) {
    tokens.put(node, newTokens);
}

No entanto, este código pode falhar por dois motivos:

  1. passa usuário um nó null.
  2. passa usuário um nó inválido, ou seja, não contida no gráfico.

Em .NET, eu jogaria um ArgumentNullException (em vez de um NullReferenceException!) ou um ArgumentException respectivamente, passando o nome do argumento agressor (node) como um argumento string.

Java não parece ter exceções equivalentes. Eu percebo que eu poderia ser mais específico e apenas jogar o que quer exceção vem mais próximo a descrevendo a situação, ou mesmo escrever minha própria classe de exceção para a situação específica.

Esta é a melhor prática? Ou existem as classes de uso geral semelhantes a ArgumentException em .NET?

Será que ainda faz sentido para verificar contra null neste caso? O código irá falhar de qualquer maneira e rastreamento de pilha da exceção irá conter a chamada do método acima. Verificando contra null parece redundante e excessiva. Concedido, o rastreamento de pilha será ligeiramente mais limpa (desde o seu alvo é o método acima, em vez de uma verificação interna na implementação HashMap do JRE). Mas isso deve ser compensado com o custo de uma instrução if adicional, que, além disso, deve não ocorrer de qualquer maneira - afinal, passando null com o método acima não é uma situação esperada, é um pouco estúpido erro. Esperando que ele é paranóico francamente - e vai falhar com a mesma exceção, mesmo se eu não verificar para ele

.

[Como tem sido apontado nos comentários, HashMap.put realmente permite valores null para a chave. Assim, um cheque contra null não seria necessariamente redundante aqui.]

Foi útil?

Solução

Diferentes grupos têm diferentes padrões.

Em primeiro lugar, eu suponho que você sabe a diferença entre RuntimeExceptions (desmarcado) e Exceptions normais (marcada), se não, então veja esta questão as respostas . Se você escrever seu próprio exceção que você pode forçá-lo a ser capturado, enquanto ambos NullPointerException e IllegalArgumentException são RuntimeExceptions que são desaprovadas em alguns círculos.

Em segundo lugar, como com você, grupos eu tenho trabalhado com, mas não ativamente o uso afirma, mas se sua equipe (ou consumidor da API) decidiu que usará afirma, então assert soa como precisamente o mecanismo correto.

Se eu fosse você eu iria usar NullPointerException. A razão para isso é precedente. Tomemos um exemplo Java API da Sun, por exemplo, java.util.TreeSet . Isto usa NPEs para precisamente este tipo de situação, e enquanto ele se parece com o código usado apenas um nulo, é inteiramente apropriado.

Como já foi dito IllegalArgumentException é uma opção, mas acho que NullPointerException é mais comunicativa.

Se esta API é projetado para ser usado por empresas de fora / equipes eu iria ficar com NullPointerException, mas certifique-se que é declarada no javadoc. Se é para uso interno, em seguida, você pode decidir que a adição de sua própria hierarquia de exceção vale a pena, mas pessoalmente acho que as APIs que adicionam enormes heirarchies de exceção, que só vão ser printStackTrace()d ou logado são apenas um desperdício de esforço.

No final do dia, a principal coisa é que seu código comunica claramente. A hierarquia de exceção local é como um jargão local -. Ele adiciona informações para insiders, mas pode confundir os forasteiros

No que respeita à verificação contra nula eu diria que faz sentido. Em primeiro lugar, ele permite que você adicione uma mensagem sobre o que era nula (ie nó ou fichas) quando você construir a exceção que seria útil. Em segundo lugar, no futuro, você pode usar uma implementação Map que permite null, e então você perderia a verificação de erro. O custo é quase nada, a menos que um profiler diz que é um problema de loop interno Eu não me preocuparia com isso.

Outras dicas

A exceção Java padrão é IllegalArgumentException. Alguns vão jogar NullPointerException se o argumento for nulo, mas para mim NPE tem que "alguém asneira" conotação, e você não quiser que os clientes da sua API para pensar que você não sabe o que está fazendo.

Para APIs públicas, verificar os argumentos e falhar cedo e limpa. O tempo / custo mal importa.

Em Java você normalmente lançar uma IllegalArgumentException

Se você quiser um guia sobre como escrever um bom código Java, recomendo o livro Java Effective por Joshua Bloch.

Parece que este poderia ser um uso apropriado para um assert :

public void setTokens(Node node, int newTokens) {
    assert node != null;
    tokens.put(node, newTokens);
}

Sua abordagem depende inteiramente do que contrato suas ofertas de função para os chamadores -? É uma condição prévia que o nó não é nulo

Se for, então você deve lançar uma exceção se o nó é nulo, uma vez que é uma violação do contrato. Se ela não é então a sua função deve silenciosamente lidar com o nulo Node e responder apropriadamente.

Eu acho que muito depende do contrato do método e quão bem o chamador é conhecido.

Em algum ponto do processo o autor da chamada pode tomar medidas para validar o nó antes de chamar o método. Se você sabe o chamador e saber que esses nós são sempre validados, então eu acho que é ok para assumir você poderá obter bons dados. Essencialmente responsabilidade está sobre o chamador.

No entanto, se você está, por exemplo, fornecendo uma biblioteca de terceiros que é distribuído então você precisa para validar o nó para valores nulos, etcs ...

Um illegalArugementException é o padrão Java, mas também é uma RuntimeException. Então, se você quiser forçar o chamador para tratar a exceção, então você precisa forneceu uma exceção de verificação, provavelmente um personalizado que você criar.

Pessoalmente eu gostaria NullPointerExceptions para acontecer somente por acidente, assim que algo mais deve ser usado para indicar que um valor de argumento ilegal foi aprovada. IllegalArgumentException é bom para isso.

if (arg1 == null) {
 throw new IllegalArgumentException("arg1 == null");
}

Isso deve ser suficiente para tanto aqueles que estão lendo o código, mas também a pobre alma que recebe uma chamada de suporte às 3 da manhã.

(e, sempre forneça um texto explicativo para as suas exceções, você irá apreciá-los algum dia triste)

como o outro: java.lang.IllegalArgumentException. Sobre a verificação nulo Node, o que sobre a verificação de entrada ruim na criação Node?

Eu não tenho que agradar ninguém, então o que eu faço agora como código canônico é

void method(String s) 

if((s != null) && (s instanceof String) && (s.length() > 0x0000))
{

que me recebe um lote de sono.

Outros vão discordar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top