Quais são alguns exemplos da vida real para entender o papel principal das afirmações?
java
assertions
Praveen
fonte
fonte
Respostas:
As asserções (por meio da palavra-chave assert ) foram adicionadas no Java 1.4. Eles são usados para verificar a correção de uma invariável no código. Eles nunca devem ser acionados no código de produção e são indicativos de um bug ou uso indevido de um caminho de código. Eles podem ser ativados no tempo de execução por meio da
-ea
opção nojava
comando, mas não são ativados por padrão.Um exemplo:
fonte
assert
para verificar os parâmetros do método público ( docs.oracle.com/javase/1.4.2/docs/guide/lang/assert.html ). Isso deve gerar um emException
vez de matar o programa.This convention is unaffected by the addition of the assert construct. Do not use assertions to check the parameters of a public method. An assert is inappropriate because the method guarantees that it will always enforce the argument checks. It must check its arguments whether or not assertions are enabled. Further, the assert construct does not throw an exception of the specified type. It can throw only an AssertionError.
docs.oracle.com/javase/8/docs/technotes/guides/language/…Vamos supor que você deva escrever um programa para controlar uma usina nuclear. É bastante óbvio que mesmo o erro mais pequeno pode ter resultados catastróficos, portanto, seu código precisa estar livre de erros (assumindo que a JVM esteja livre de erros por causa do argumento).
Java não é uma linguagem verificável, o que significa: você não pode calcular que o resultado da sua operação será perfeito. A principal razão para isso são os ponteiros: eles podem apontar para qualquer lugar ou lugar nenhum; portanto, não podem ser calculados com esse valor exato, pelo menos não dentro de um intervalo razoável de código. Dado esse problema, não há como provar que seu código está correto em geral. Mas o que você pode fazer é provar que você encontra pelo menos todos os erros quando isso acontece.
Essa idéia é baseada no paradigma Design por Contrato (DbC): você primeiro define (com precisão matemática) o que seu método deve fazer e depois verifica isso testando-o durante a execução real. Exemplo:
Embora isso seja bastante óbvio para funcionar bem, a maioria dos programadores não verá o bug oculto dentro deste (dica: o Ariane V travou por causa de um bug semelhante). Agora, o DbC define que você deve sempre verificar a entrada e a saída de uma função para verificar se ela funcionou corretamente. Java pode fazer isso através de afirmações:
Se essa função agora falhar, você notará. Você saberá que há um problema no seu código, você sabe onde ele está e o que o causou (semelhante a Exceções). E o que é ainda mais importante: você para de executar corretamente quando isso acontece, para impedir que qualquer código adicional funcione com valores errados e, potencialmente, cause danos ao que ele controla.
Exceções de Java são um conceito semelhante, mas não conseguem verificar tudo. Se você quiser ainda mais verificações (ao custo da velocidade de execução), precisará usar asserções. Fazer isso inchará seu código, mas no final você poderá entregar um produto em um tempo de desenvolvimento surpreendentemente curto (quanto mais cedo você corrigir um bug, menor será o custo). Além disso: se houver algum bug dentro do seu código, você o detectará. Não há como escapar de um bug e causar problemas mais tarde.
Isso ainda não é garantia de código sem erros, mas é muito mais próximo disso do que os programas comuns.
fonte
new IllegalArgumentException
com a mensagem? Quero dizer, além de ter que adicionarthrows
à declaração do método e ao código para gerenciar essa exceção em outro lugar. Por queassert
insetad de lançar nova exceção? Ou por que não um emif
vez deassert
? Realmente não consigo fazer isso :(a
puder ser negativa. A segunda afirmação é inútil; para valores int, é sempre o caso em que a + b - b == a. Esse teste só pode falhar se o computador estiver fundamentalmente quebrado. Para se defender dessa contingência, é necessário verificar a consistência em várias CPUs.As asserções são uma ferramenta da fase de desenvolvimento para detectar erros no seu código. Eles foram projetados para serem facilmente removidos, para que não existam no código de produção. Portanto, as asserções não fazem parte da "solução" que você entrega ao cliente. São verificações internas para garantir que as suposições que você está fazendo estejam corretas. O exemplo mais comum é testar se é nulo. Muitos métodos são escritos assim:
Muitas vezes, em um método como esse, o widget simplesmente nunca deve ser nulo. Portanto, se for nulo, há um erro no seu código em algum lugar que você precisa rastrear. Mas o código acima nunca lhe dirá isso. Portanto, em um esforço bem-intencionado para escrever código "seguro", você também está ocultando um bug. É muito melhor escrever código como este:
Dessa forma, você terá certeza de capturar esse bug mais cedo. (Também é útil especificar no contrato que esse parâmetro nunca deve ser nulo.) Certifique-se de ativar as asserções ao testar seu código durante o desenvolvimento. (E convencer seus colegas a fazer isso também é muitas vezes difícil, o que eu acho muito irritante.)
Agora, alguns de seus colegas se oporão a esse código, argumentando que você ainda deve colocar a verificação nula para evitar uma exceção na produção. Nesse caso, a afirmação ainda é útil. Você pode escrever assim:
Dessa forma, seus colegas ficarão felizes com a verificação nula do código de produção, mas durante o desenvolvimento, você não estará mais ocultando o erro quando o widget for nulo.
Aqui está um exemplo do mundo real: Certa vez, escrevi um método que comparava dois valores arbitrários para igualdade, em que qualquer valor poderia ser nulo:
Esse código delega o trabalho do
equals()
método no caso em que thisValue não é nulo. Mas ele pressupõe que oequals()
método cumpra corretamente o contratoequals()
, manipulando adequadamente um parâmetro nulo.Um colega se opôs ao meu código, dizendo-me que muitas de nossas classes têm
equals()
métodos de buggy que não testam nulo; portanto, eu deveria colocar essa verificação nesse método. É discutível se isso é sensato, ou se devemos forçar o erro, para que possamos identificá-lo e corrigi-lo, mas adiei ao meu colega e fiz uma verificação nula, que marquei com um comentário:A verificação adicional aqui,
other != null
é necessária apenas se oequals()
método falhar na verificação de nulo, conforme exigido por seu contrato.Em vez de entrar em um debate infrutífero com meu colega sobre a sabedoria de deixar o código de buggy permanecer em nossa base de código, simplesmente coloquei duas asserções no código. Essas afirmações me informarão, durante a fase de desenvolvimento, se uma de nossas classes falhar na implementação
equals()
adequada, para que eu possa corrigi-lo:Os pontos importantes a serem lembrados são os seguintes:
As asserções são apenas ferramentas da fase de desenvolvimento.
O objetivo de uma afirmação é informar se há um erro, não apenas no seu código, mas em sua base de código . (As asserções aqui realmente sinalizam bugs em outras classes.)
Mesmo que meu colega estivesse confiante de que nossas aulas foram escritas adequadamente, as afirmações aqui ainda seriam úteis. Novas classes serão adicionadas que podem falhar no teste de nulo, e esse método pode sinalizar esses erros para nós.
No desenvolvimento, você sempre deve ativar as asserções, mesmo que o código que você escreveu não use asserções. Meu IDE está configurado para sempre fazer isso por padrão para qualquer novo executável.
As asserções não alteram o comportamento do código na produção; portanto, meu colega está feliz por a verificação nula estar presente e por esse método ser executado corretamente, mesmo que o
equals()
método seja com erros. Estou feliz porque vou pegar qualquerequals()
método de buggy no desenvolvimento.Além disso, você deve testar sua política de asserção inserindo uma asserção temporária que falhará, para ter certeza de que será notificado por meio do arquivo de log ou de um rastreamento de pilha no fluxo de saída.
fonte
Muitas respostas boas explicando o que a
assert
palavra - chave faz, mas poucas respondendo à pergunta real ", quando oassert
palavra chave ser usada na vida real?"A resposta: quase nunca .
As asserções, como conceito, são maravilhosas. Um bom código tem muitas
if (...) throw ...
instruções (e seus parentes gostamObjects.requireNonNull
eMath.addExact
). No entanto, certas decisões de design limitaram bastante a utilidade da palavra -assert
chave própria - .A ideia principal por trás da
assert
palavra-chave é a otimização prematura, e o principal recurso é poder desativar facilmente todas as verificações. De fato, oassert
verificações são desativadas por padrão.No entanto, é extremamente importante que verificações invariantes continuem sendo feitas na produção. Isso ocorre porque a cobertura perfeita do teste é impossível, e todo código de produção terá bugs, que afirmações devem ajudar a diagnosticar e mitigar.
Portanto, o uso de
if (...) throw ...
deve ser preferido, assim como é necessário para verificar valores de parâmetros de métodos públicos e para jogarIllegalArgumentException
.Ocasionalmente, pode-se sentir tentado a escrever um cheque invariável que leva um tempo indesejável a ser processado (e é chamado com frequência suficiente para que isso importe). No entanto, essas verificações retardarão os testes, o que também é indesejável. Tais verificações demoradas são geralmente escritas como testes de unidade. No entanto, às vezes pode fazer sentido usar
assert
por esse motivo.Não use
assert
simplesmente porque é mais limpo e mais bonito do queif (...) throw ...
(e digo isso com muita dor, porque gosto de limpo e bonito). Se você simplesmente não pode ajudar a si mesmo e pode controlar como o aplicativo é iniciado, fique à vontade para usar,assert
mas sempre habilite asserções na produção. É certo que é isso que eu costumo fazer. Estou pressionando por uma anotação de lombok que fará comassert
que seja mais parecidoif (...) throw ...
. Vote aqui.(Discurso: os desenvolvedores da JVM eram um monte de codificadores horríveis e otimizavam prematuramente. É por isso que você ouve tantos problemas de segurança no plug-in Java e na JVM. Eles se recusaram a incluir verificações e asserções básicas no código de produção, e continuamos a pague o preço.)
fonte
catch (Throwable t)
. Não há nenhuma razão para não tentar armadilha, log, ou repetição / recuperar de OutOfMemoryError, AssertionError, etc.assert
palavra-chave é ruim. Editarei minha resposta para deixar mais claro que estou me referindo à palavra-chave, não ao conceito.Aqui está o caso de uso mais comum. Suponha que você esteja ativando um valor enum:
Contanto que você lide com todos os casos, você está bem. Mas um dia alguém adicionará figo à sua enumeração e esquecerá de adicioná-lo à sua declaração de troca. Isso produz um bug que pode ser complicado de detectar, porque os efeitos não serão sentidos até que você tenha deixado a instrução switch. Mas se você escrever seu switch assim, poderá capturá-lo imediatamente:
fonte
AssertionError
se as asserções estiverem ativadas (-ea
). Qual é o comportamento desejado na produção? Um desastre silencioso no-op e potencial mais tarde na execução? Provavelmente não. Eu sugeriria um explícitothrow new AssertionError("Missing enum value: " + fruit);
.default
para que o compilador possa avisar sobre casos ausentes. Você pode, emreturn
vez debreak
(pode ser necessário extrair o método) e, em seguida, manipular o caso ausente após a troca. Dessa forma, você recebe o aviso e uma oportunidadeassert
.As asserções são usadas para verificar pós-condições e "nunca devem falhar" pré-condições. O código correto nunca deve falhar em uma afirmação; quando acionados, devem indicar um erro (espero que esteja em um local próximo ao local onde está o problema).
Um exemplo de asserção pode ser verificar se um determinado grupo de métodos é chamado na ordem correta (por exemplo, que
hasNext()
é chamado anteriormentenext()
em umIterator
).fonte
Vamos dar uma olhada no código de código compilado.
Concluiremos que:
gera quase exatamente o mesmo bytecode que:
onde
Assert.class.desiredAssertionStatus()
étrue
quando-ea
é passado na linha de comando e falso caso contrário.Usamos
System.currentTimeMillis()
para garantir que ele não seja otimizadoassert true;
.O campo sintético é gerado para que o Java precise chamar apenas
Assert.class.desiredAssertionStatus()
uma vez no tempo de carregamento e, em seguida, armazena em cache o resultado lá. Veja também: Qual é o significado de "sintético estático"?Podemos verificar isso com:
Com o Oracle JDK 1.8.0_45, um campo estático sintético foi gerado (consulte também: Qual é o significado de "sintético estático"? ):
junto com um inicializador estático:
e o método principal é:
Concluimos que:
assert
: é um conceito de linguagem Javaassert
pode ser emulado muito bem com as propriedades do sistema-Pcom.me.assert=true
para substituir-ea
na linha de comando e athrow new AssertionError()
.fonte
catch (Throwable t)
cláusula é capaz de detectar violações de afirmações também? Para mim, isso limita sua utilidade apenas ao caso em que o corpo da afirmação consome tempo, o que é raro.AssertionError
primeiro e repeti-lo novamente.Um exemplo do mundo real, de uma classe Stack (de Assertion in Java Articles )
fonte
Uma asserção permite detectar defeitos no código. Você pode ativar asserções para teste e depuração enquanto as deixa desativadas quando o programa está em produção.
Por que afirmar algo quando você sabe que é verdade? Só é verdade quando tudo está funcionando corretamente. Se o programa tiver um defeito, pode não ser verdade. Detectar isso no início do processo permite saber que algo está errado.
Uma
assert
declaração contém essa declaração junto com umaString
mensagem opcional .A sintaxe para uma declaração assert possui duas formas:
Aqui estão algumas regras básicas que governam onde as asserções devem ser usadas e onde elas não devem ser usadas. As asserções devem ser usadas para:
Validando parâmetros de entrada de um método privado. NÃO para métodos públicos.
public
métodos devem lançar exceções regulares quando passados parâmetros inválidos.Em qualquer lugar do programa para garantir a validade de um fato quase certo.
Por exemplo, se você tiver certeza de que será apenas 1 ou 2, poderá usar uma asserção como esta:
As afirmações não devem ser usadas para:
Validando parâmetros de entrada de um método público. Como as asserções nem sempre podem ser executadas, o mecanismo de exceção regular deve ser usado.
Validando restrições em algo que é inserido pelo usuário. O mesmo que acima.
Não deve ser usado para efeitos colaterais.
Por exemplo, este não é um uso adequado, porque aqui a asserção é usada para o efeito colateral da chamada do
doSomething()
método.O único caso em que isso pode ser justificado é quando você está tentando descobrir se as asserções estão ou não ativadas no seu código:
fonte
Além de todas as ótimas respostas fornecidas aqui, o guia de programação oficial do Java SE 7 possui um manual bastante conciso sobre o uso
assert
; com vários exemplos pontuais de quando é uma boa (e, principalmente, ruim) idéia de usar asserções e como é diferente de lançar exceções.Ligação
fonte
Afirmar é muito útil ao desenvolver. Você o usa quando algo simplesmente não pode acontecer se seu código estiver funcionando corretamente. É fácil de usar e pode permanecer no código para sempre, porque será desativado na vida real.
Se houver alguma chance de a condição ocorrer na vida real, você deve lidar com isso.
Adoro, mas não sei como ativá-lo no Eclipse / Android / ADT. Parece estar desativado mesmo durante a depuração. (Existe um encadeamento sobre isso, mas refere-se ao 'Java vm', que não aparece na Configuração de Execução do ADT).
fonte
Aqui está uma afirmação que escrevi em um servidor para um projeto Hibernate / SQL. Um bean de entidade tinha duas propriedades efetivamente booleanas, chamadas isActive e isDefault. Cada um poderia ter um valor de "Y" ou "N" ou nulo, que foi tratado como "N". Queremos garantir que o cliente do navegador esteja limitado a esses três valores. Então, nos meus levantadores para essas duas propriedades, adicionei esta asserção:
Observe o seguinte.
Esta afirmação é apenas para a fase de desenvolvimento. Se o cliente enviar um valor ruim, pegaremos isso cedo e o corrigiremos, muito antes de chegarmos à produção. As asserções são para defeitos que você pode detectar cedo.
Essa afirmação é lenta e ineficiente. Tudo bem. As afirmações são livres para serem lentas. Não nos importamos porque são ferramentas apenas para desenvolvimento. Isso não desacelerará o código de produção porque as asserções serão desativadas. (Há alguma discordância sobre esse ponto, que abordarei mais adiante.) Isso leva ao meu próximo ponto.
Esta afirmação não tem efeitos colaterais. Eu poderia ter testado meu valor em relação a um conjunto final estático não modificável, mas esse conjunto permaneceria em produção, onde nunca seria usado.
Esta asserção existe para verificar o bom funcionamento do cliente. Assim, quando chegarmos à produção, teremos certeza de que o cliente está operando corretamente, para que possamos desativar com segurança a afirmação.
Algumas pessoas perguntam o seguinte: se a afirmação não é necessária na produção, por que não retirá-las quando terminar? Porque você ainda precisará deles quando começar a trabalhar na próxima versão.
Algumas pessoas argumentaram que você nunca deve usar afirmações, porque você nunca pode ter certeza de que todos os bugs se foram, portanto, é necessário mantê-los por perto, mesmo na produção. E, portanto, não faz sentido usar a declaração assert, pois a única vantagem de afirmar é que você pode desativá-los. Portanto, de acordo com esse pensamento, você nunca deve (quase) usar afirmações. Discordo. Certamente é verdade que, se um teste pertencer à produção, você não deve usar uma declaração. Mas esse teste não pertence à produção. Este é para detectar um erro que provavelmente nunca alcançará a produção, portanto, ele pode ser desativado com segurança quando você terminar.
BTW, eu poderia ter escrito assim:
Isso é bom para apenas três valores, mas se o número de valores possíveis aumentar, a versão do HashSet se tornará mais conveniente. Eu escolhi a versão HashSet para enfatizar minha eficiência.
fonte
HashSet
traz qualquer vantagem de velocidade ao longo de umArrayList
. Além disso, as criações de conjunto e lista dominam o tempo de pesquisa. Eles ficariam bem ao usar uma constante. Isso dito, +1.A asserção é basicamente usada para depurar o aplicativo ou é usada na substituição do tratamento de exceções de algum aplicativo para verificar a validade de um aplicativo.
A asserção funciona em tempo de execução. Um exemplo simples, que pode explicar todo o conceito de maneira muito simples, está aqui - O que a palavra-chave assert faz em Java? (Respostas da Wiki).
fonte
As asserções estão desabilitadas por padrão. Para habilitá-los, precisamos executar o programa com
-ea
opções (a granularidade pode variar). Por exemplojava -ea AssertionsDemo
,.Existem dois formatos para usar asserções:
assert 1==2; // This will raise an AssertionError
.assert 1==2: "no way.. 1 is not equal to 2";
Isso gerará um AssertionError com a mensagem fornecida exibida também e, portanto, é melhor. Embora a sintaxe real sejaassert expr1:expr2
onde expr2 possa ser qualquer expressão retornando um valor, eu a usei com mais frequência apenas para imprimir uma mensagem.fonte
Para recapitular (e isso vale para muitas linguagens, não apenas para Java):
"assert" é usado principalmente como auxiliar de depuração por desenvolvedores de software durante o processo de depuração. As mensagens de afirmação nunca devem aparecer. Muitos idiomas fornecem uma opção em tempo de compilação que fará com que todas as "declarações" sejam ignoradas, para uso na geração de código de "produção".
"exceções" são uma maneira prática de lidar com todos os tipos de condições de erro, independentemente de representarem erros lógicos, porque, se você encontrar uma condição de erro que não possa continuar, pode simplesmente "jogá-la no ar, "de onde você estiver, esperando que outra pessoa esteja pronta para" pegá-la ". O controle é transferido em uma etapa, direto do código que lançou a exceção, direto para a luva do coletor. (E o apanhador pode ver o rastreamento completo das chamadas que ocorreram.)
Além disso, os chamadores dessa sub-rotina não precisam verificar se a sub-rotina foi bem-sucedida: "se estamos aqui agora, ela deve ter sido bem-sucedida, porque, caso contrário, isso geraria uma exceção e não estaríamos aqui agora!" Essa estratégia simples facilita muito o design e a depuração do código.
As exceções permitem convenientemente que as condições de erro fatal sejam o que são: "exceções à regra". E, para eles serem manipulados por um caminho de código que também é "uma exceção à regra ... " fly ball!
fonte
Asserções são verificações que podem ser desativadas. Eles raramente são usados. Por quê?
result != null
pois essas verificações são muito rápidas e não há quase nada a ser salvo.Então, o que resta? Verificações caras de condições realmente esperadas são verdadeiras. Um bom exemplo seria os invariantes de uma estrutura de dados como a RB-tree. Na verdade, no
ConcurrentHashMap
JDK8, existem algumas afirmações significativas para oTreeNodes
.Às vezes, o cheque não é muito caro, mas, ao mesmo tempo, você tem certeza de que será aprovado. No meu código, há, por exemplo,
onde tenho certeza de que a lista que acabei de criar possui elementos únicos, mas queria documentá-la e checá-la duas vezes.
fonte
Basicamente, "afirmar verdadeiro" passará e "afirmar falso" falhará. Vamos ver como isso funcionará:
fonte
assert
é uma palavra-chave. Foi introduzido no JDK 1.4. Existem dois tipos deassert
sassert
Declarações muito simplesassert
Declarações simples .Por padrão, todas as
assert
instruções não serão executadas. Se umaassert
instrução receber falsa, ela gerará automaticamente um erro de asserção.fonte