Quando usar uma asserção e quando usar uma exceção

121

Na maioria das vezes, usarei uma exceção para verificar uma condição no meu código. Gostaria de saber quando é o momento apropriado para usar uma asserção?

Por exemplo,

Group group=null;
try{
    group = service().getGroup("abc");
}catch(Exception e){
    //I dont log error because I know whenever error occur mean group not found
}

if(group !=null)
{
    //do something
}

Você poderia indicar como uma afirmação se encaixa aqui? Devo usar uma afirmação?

Parece que eu nunca uso asserções no código de produção e apenas vejo asserções em testes de unidade. Eu sei que, na maioria dos casos, posso apenas usar a exceção para fazer a verificação como acima, mas quero saber a maneira apropriada de fazer isso "profissionalmente".

cometta
fonte

Respostas:

81

As asserções devem ser usadas para verificar algo que nunca deve acontecer, enquanto uma exceção deve ser usada para verificar algo que pode acontecer.

Por exemplo, uma função pode ser dividida por 0, portanto, uma exceção deve ser usada, mas uma asserção pode ser usada para verificar se o disco rígido desaparece subitamente.

Uma asserção interromperia a execução do programa, mas uma exceção deixaria o programa continuar em execução.

Observe que if(group != null)não é uma afirmação, é apenas uma condicional.

Marius
fonte
3
"uma afirmação pode ser usada para verificar se o disco rígido desaparece repentinamente" - eu diria que isso não está correto: por que você deseja que isso seja tratado durante o desenvolvimento, mas não na produção (quando as afirmações geralmente são desativadas)?
Herman
71
O comentário sobre o disco rígido está errado. As asserções são para verificar erros na sua lógica de código. Nunca, jamais, use-os para verificar algo que você não controla. Lembre- se , se uma afirmação falhar, significa que seu código está errado .
Ian Goldby
1
@Marius sua condicional poderia ser substituído por uma afirmação como esta: grupo assert = null
IgorGanapolsky
1
Votado porque o exemplo do disco rígido contradiz sua própria filosofia. Discos rígidos "desaparecendo" (da perspectiva do código) podem realmente acontecer na realidade - não importa o quão improvável. Como o @IanGoldby diz, as afirmações devem depender puramente das coisas controladas pelo seu código.
Vicky Chijwani
Uma resposta muito melhor, se publicado por Gregory Pakosz, leia esse post.
Ormurin 04/04/19
169

Fora da minha cabeça (a lista pode estar incompleta e é muito longa para caber em um comentário), eu diria:

  • use exceções ao verificar parâmetros passados ​​para métodos e construtores públicos ou protegidos
  • use exceções ao interagir com o usuário ou quando você espera que o código do cliente se recupere de uma situação excepcional
  • use exceções para resolver problemas que possam ocorrer
  • use asserções ao verificar pré-condições, pós-condições e invariantes de código privado / interno
  • use asserções para fornecer feedback para você ou sua equipe de desenvolvedores
  • use asserções ao verificar se é muito improvável que isso aconteça, caso contrário, significa que há um problema sério no seu aplicativo
  • use asserções para declarar coisas que você (supostamente) sabe ser verdade

Em outras palavras, as exceções tratam da robustez do seu aplicativo, enquanto as afirmações tratam da exatidão.

As asserções são projetadas para serem baratas de escrever, você pode usá-las em quase todos os lugares e eu estou usando esta regra geral: quanto mais uma declaração de asserção parecer estúpida, mais valiosa e mais informações serão incorporadas. Ao depurar um programa que não se comporta da maneira correta, você certamente verificará as possibilidades de falha mais óbvias com base em sua experiência. Depois, você verificará problemas que simplesmente não podem acontecer: é exatamente quando as asserções ajudam muito e economizam tempo.

Gregory Pakosz
fonte
53
Gosto da maneira como você formulou isso: as exceções tratam da robustez do seu aplicativo enquanto as afirmações tratam da exatidão .
M. Dudley
Cruzei postado no meu site: pempek.net/articles/2013/11/16/assertions-or-exceptions
Gregory Pakosz
E, se você procurar uma biblioteca de afirmação personalizada em C ++, lancei github.com/gpakosz/Assert
Gregory Pakosz
26

Lembre-se de que as asserções podem ser desabilitadas em tempo de execução usando parâmetros e são desabilitadas por padrão ; portanto, não conte com elas, exceto para fins de depuração.

Além disso, você deve ler o artigo da Oracle sobre assert para ver mais casos em que usar - ou não usar - assert.

chburd
fonte
Hue hue hue Fiquei me perguntando por que meu código estava falhando no Eclipse, mas rodando bem na linha de comando.
Steve
15

Como uma regra geral:

  • Use asserções para verificações de consistência interna, onde não importa se alguém as desativa. (Observe que o javacomando desativa todas as asserções por padrão.)
  • Use testes regulares para qualquer tipo de verificação que não deva ser desativada. Isso inclui verificações defensivas que se protegem contra possíveis danos causados ​​por bugs e quaisquer dados / solicitações de validação / o que for fornecido por usuários ou serviços externos.

O código a seguir da sua pergunta é de estilo incorreto e potencialmente com erros

try {
    group = service().getGroup("abc");
} catch (Exception e) {
    //i dont log error because i know whenever error occur mean group not found
}

O problema é que você NÃO sabe que uma exceção significa que o grupo não foi encontrado. Também é possível que a service()chamada tenha lançado uma exceção ou retornada, o nullque causou a NullPointerException.

Ao capturar uma exceção "esperada", você deve capturar apenas a exceção que está esperando. Ao capturar java.lang.Exception(e principalmente ao não registrá-lo), você está dificultando o diagnóstico / depuração do problema e potencialmente permitindo que o aplicativo cause mais danos.

Stephen C
fonte
4

Bem, na Microsoft, a recomendação era lançar exceções em todas as APIs que você disponibilizar publicamente e usar o Asserts em todos os tipos de suposições feitas sobre códigos internos. É um pouco de uma definição frouxa, mas acho que cabe a cada desenvolvedor traçar a linha.

Em relação ao uso de exceções, como o nome indica, o uso delas deve ser excepcional. Portanto, para o código que você apresenta acima, a getGroupchamada deve retornar nullse não houver serviço. A exceção só deve ocorrer se um link de rede cair ou algo parecido.

Acho que a conclusão é que é um pouco deixado para a equipe de desenvolvimento de cada aplicativo definir os limites de assert vs vs excepções.

rui
fonte
IMHO, o problema com esse tipo de recomendação é que não há problema, desde que o limite entre as partes pública e privada de uma API seja bastante fixo. Se você está desenvolvendo um novo código, em seguida, esse limite é muitas vezes bastante fluido ...
Len Holgate
Sim, você está certo. É uma diretriz, mas no final do dia é deixada de fora para a sensibilidade dos programadores. Eu não acho que exista uma linha definitiva para eles, então acho que você segue o que acha certo ao ler um monte de código diferente.
rui
3

De acordo com este documento http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#design-faq-general , "A declaração assert é apropriada para pré-condição não pública, pós-condição e classe invariável A verificação de pré-condição pública ainda deve ser realizada por verificações dentro de métodos que resultam em exceções documentadas, como IllegalArgumentException e IllegalStateException. "

Se você quiser saber mais sobre pré-condição, pós-condição e invariáveis ​​de classe, consulte este documento: http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#usage-conditions . Ele também contém exemplos de uso de asserções.

cesarsalgado
fonte
1

O teste de nulo somente captura nulos causando problemas, enquanto que uma tentativa / captura, como você a possui, detectará qualquer erro.

Em termos gerais, a tentativa / captura é mais segura, mas um pouco mais lenta, e você deve ter cuidado para encontrar todos os tipos de erros que possam ocorrer. Então, eu diria que use try / catch - um dia o código getGroup pode mudar, e você pode precisar dessa rede maior.

Phil H
fonte
1

Você pode usar essa diferença simples em mente enquanto estiver usando. Exceções serão usadas para verificar os erros esperados e inesperados, chamados de erro verificado e não verificado, enquanto a asserção é usada principalmente para fins de depuração no tempo de execução, para verificar se as premissas são validadas ou não.

SBTec
fonte
1

Confesso que estou um pouco confuso com sua pergunta. Quando uma condição de asserção não é atendida, uma exceção é lançada. Confusamente, isso é chamado de AssertionError . Observe que está desmarcada, como (por exemplo) IllegalArgumentException, lançada em circunstâncias muito semelhantes.

Então, usando asserções em Java

  1. é um meio mais conciso de escrever um bloco de condição / lançamento
  2. permite ativar / desativar essas verificações através dos parâmetros da JVM. Normalmente, eu deixava essas verificações o tempo todo, a menos que elas afetassem o desempenho do tempo de execução ou tivessem uma penalidade semelhante.
Brian Agnew
fonte
AssertionError é uma subclasse de Error not RuntimeException.
Stephen C
Ah Claro. Eu estava pensando em marcado / desmarcado. Agora corrigido
Brian Agnew
Explica o que são asserções (de um ponto de vista controverso), mas não quando usá-las exatamente.
Karl Richter
1

Consulte a seção 6.1.2 (Declarações versus outro código de erro) da documentação da Sun no link a seguir.

http://www.oracle.com/technetwork/articles/javase/javapch06.pdf

Este documento fornece os melhores conselhos que já vi sobre quando usar asserções. Citando o documento:

"Uma boa regra geral é que você deve usar uma asserção para casos excepcionais que gostaria de esquecer. Uma asserção é a maneira mais rápida de lidar e esquecer uma condição ou estado que você não espera que Lide com."

Phil
fonte
0

Infelizmente, as declarações podem ser desativadas. Quando em produção, você precisa de toda a ajuda possível para rastrear algo imprevisto, de modo que as declarações se desqualificam.

Thorbjørn Ravn Andersen
fonte