Pergunta

Estou me perguntando por que o assert A palavra -chave é tão subutilizada em Java? Quase nunca os vi usados, mas acho que eles são uma ótima ideia. Eu certamente prefiro a brevidade de:

assert param != null : "Param cannot be null";

para a verbosidade de:

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

Minha suspeita é que eles são subutilizados porque

  • Eles chegaram relativamente tarde (Java 1.4), quando muitas pessoas já haviam estabelecido seu estilo/hábito de programação Java
  • Eles estão desligados em tempo de execução por padrão
Foi útil?

Solução

afirmações são, em teoria, para testar invariantes, suposições que devo Seja verdadeiro para que o código seja concluído corretamente.

O exemplo mostrado é testar para entrada válida, o que não é um uso típico para uma afirmação, porque é geralmente fornecido pelo usuário.

As afirmações geralmente não são usadas no código de produção porque há uma sobrecarga e supõe -se que as situações em que os invariantes falhem foram capturados como erros de codificação durante o desenvolvimento e o teste.

Seu ponto de vista sobre eles chegando "atrasado" para Java também é uma razão pela qual eles não são mais vistos.

Além disso, as estruturas de teste de unidade permitem que parte da necessidade de asserções programáticas sejam externas ao código que está sendo testado.

Outras dicas

É um abuso de afirmações usá -las para testar a entrada do usuário. Jogando um IllegalArgumentException Na entrada inválida é mais correta, pois permite que o método de chamada capta a exceção, exiba o erro e faça o que for necessário (peça a entrada novamente, desista, seja o que for).

Se esse método é um método privado dentro de uma de suas classes, a afirmação é boa, porque você está apenas tentando garantir que não está passando acidentalmente um argumento nulo. Você testa com as afirmações e, quando você testou todos os caminhos e não acionou a afirmação, pode desligá -los para que não esteja desperdiçando recursos neles. Eles também são úteis, assim como comentários. Um assert No início de um método está uma boa documentação para os mantenedores de que eles deveriam estar seguindo certas pré -condições e um assert No final, com um documento pós -condicionamento, o que o método deveria estar fazendo. Eles podem ser tão úteis quanto comentários; mais, porque com as afirmações, eles realmente testam o que documentam.

As afirmações são para testar/depuração, não a verificação de erros, e é por isso que eles estão desativados por padrão: desencorajar as pessoas de usar as afirmações para validar a entrada do usuário.

A partir de Programação com afirmações

Por padrão, as afirmações são desativadas em tempo de execução. Dois interruptores de linha de comando permitem ativar ou desativar seletivamente as afirmações.

Isso significa que, se você não tiver controle completo sobre o ambiente de tempo de execução, não poderá garantir que o código de asserção seja chamado. As afirmações devem ser usadas em um ambiente de teste, não para o código de produção. Você não pode substituir o manuseio de exceção por afirmações, porque se o usuário executar seu aplicativo com asserções desativadas (o predefinição), todo o seu código de manuseio de erros desaparece.

Em "Java eficaz", Joshua Bloch sugeriu (nos "parâmetros de verificação de validade" tópico) que (mais ou menos uma regra simples de adotar), para métodos públicos, validaremos os argumentos e lançaremos a exceção necessária se for encontrado inválido, e Para métodos não públicos (que não são expostos e você, como usuário deles, deve garantir sua validade), podemos usar a afirmação.

yc

@Don, você está frustrado por a afirmação ser desligada por padrão. Eu também estava e, assim if (!expr) throw Ex em vez de esse bytecode afirmar bobo.

Se você incluir fa.jar Em seu caminho de classe enquanto compilam o código Java, ele fará sua mágica e depois diz

Note: %n assertions inlined.

@Vejo http://smallwiki.unibe.ch/adriankuhn/javacompiler/forceassertions e alternativamente no github https://github.com/akuhn/javac

Não sei por que você se preocuparia em escrever afirma e depois substituí -los por uma declaração padrão se depois condicionar, por que não apenas escrever as condições como se, em primeiro lugar?

As afirmam apenas para testes e eles têm dois efeitos colaterais: binários maiores e desempenho degradado quando ativado (e é por isso que você pode desligá -los!)

As afirmam que não devem ser usadas para validar condições, porque isso significa que o comportamento do seu aplicativo é diferente no tempo de execução quando as afirmações são ativadas/desativadas - o que é um pesadelo!

Assertions are useful because they:

  • catch PROGRAMMING errors early
  • document code using code

Think of them as code self-validation. If they fail it should mean that your program is broken and must stop. Always turn them on while unit testing !

In The Pragmatic Programmer they even recommend to let them run in production.

Leave Assertions Turned On

Use Assertions to Prevent the Impossible.

Note that assertions throw AssertionError if they fail, so not caught by catch Exception.

Assertions are very limited: You can only test boolean conditions and you need to write the code for a useful error message every time. Compare this to JUnit's assertEquals() which allows to generate a useful error message from the inputs and even show the two inputs side by side in the IDE in a JUnit runner.

Also, you can't search for assertions in any IDE I've seen so far but every IDE can search for method invocations.

In fact they arrived in Java 1.4

I think the main problem is that when you code in an environment where you do not manage directly jvm options by yourself like in eclipse or J2EE servers (in both cases it is possible to change jvm options but you need to deeply search to find where it can be done), it is easier (I mean it requires less effort) to use if and exceptions (or worse not to use anything).

As others have stated: assertions are not appropriate for validating user input.

If you are concerned with verbosity, I recommend you check out a library I wrote: https://bitbucket.org/cowwoc/requirements/. It'll allow you to express these checks using very little code, and it'll even generate the error message on your behalf:

requireThat("name", value).isNotNull();

and if you insist on using assertions, you can do this too:

assertThat("name", value).isNotNull();

The output will look like this:

java.lang.NullPointerException: name may not be null

tl;dr

  • Yes, use assertion-testing in production where it makes sense.
  • Use other libraries (JUnit, AssertJ, Hamcrest, etc.) rather than the built-in assert facility if you wish.

Most of the other Answers on this page push the maxim "Assertions aren't generally used in production code”. While true in productivity apps such as a word-processor or spreadsheet, in custom business apps where Java is so commonly used, assertion-testing in production is extremely useful, and common.

Like many maxims in the world of programming, what starts out true in one context is misconstrued and then misapplied in other contexts.

Productivity Apps

This maxim of "Assertions aren't generally used in production code”, though common, is incorrect.

Formalized assertion-testing originated with apps such as a word-processor like Microsoft Word or a spreadsheet like Microsoft Excel. These apps might invoke an array of assertion tests assertions on every keystroke made by the user. Such extreme repetition impacted performance severely. So only the beta-versions of such products in limited distribution had assertions enabled. Thus the maxim.

Business Apps

In contrast, in business-oriented apps for data-entry, database, or other data-processing, the use of assertion-testing in production is enormously useful. The insignificant hit on performance makes it quite practical – and common.

Test business rules

Verifying your business rules at runtime in production is entirely reasonable, and should be encouraged. For example, if an invoice must have one or more line items at all times, then write an assertion testing than the count of invoice line items is greater than zero. If a product name must be at least 3 characters or more, write an assertion testing the length of the string. Such tests have no significant impact on performance in production.

Runtime conditions

If your app expects certain conditions to always be true when your app runs in production, write those expectations into your code as assertion tests.

If you expect those conditions may reasonably on occasion fail, then do not write assertion tests. Perhaps throw certain exceptions. Then try to recover where possible.

Sanity-checks

Sanity checks at runtime in production is also entirely reasonable, and should be encouraged. Testing a few arbitrary conditions that one could not imagine being untrue has saved my bacon in countless situations when some bizarre happening occurred.

For example, testing that rounding a nickel (0.05) to the penny resulted in a nickel (0.05) in a certain library helped me in being one of the first people to discover a floating-point technology flaw that Apple shipped in their Rosetta library during the PowerPC-to-Intel transition. Such a flaw reaching the public would have seemed impossible. But amazingly, the flaw had escaped the notice of the originating vendor, Transitive, and Apple, and the early-access developers testing on Apple’s betas.

(By the way, I should mention… never use floating-point for money, use BigDecimal.)

Choice of frameworks

Rather than use the built-in assert facility, you may want to consider using another assertion framework. You have multiple options, including:

Or roll-your-own. Make a little class to use in your project. Something like this.

package work.basil.example;

public class Assertions {
    static public void assertTrue ( Boolean booleanExpression , CharSequence message ) throws java.lang.AssertionError {
        if ( booleanExpression ) {
            // No code needed here.
        } else { // If booleanExpression is false rather than expected true, throw assertion error.
            // FIXME: Add logging.
            throw new java.lang.AssertionError( message.toString() );
        }
    }

}

Example usage:

Assertions.assertTrue( 
    localTime.isBefore( LocalTime.NOON ) , 
    "The time-of-day is too late, after noon: " + localTime + ". Message # 816a2a26-2b95-45fa-9b0a-5d10884d819d." 
) ;

Your questions

They arrived relatively late (Java 1.4), by which time many people had already established their Java programming style/habit

Yes, this is quite true. Many people were disappointed by the API that Sun/JCP developed for assertion-testing. Its design was lackluster in comparison to existing libraries. So many ignored the new API, and stuck with known tools (3rd-party tools, or roll-your-own mini-library).

They are turned off at runtime by default, WHY OH WHY??

In the earliest years, Java got a bad rap for poor performance speed. Ironically, Java quickly evolved to become one of the best platforms for performance. But the bad rap hung around like a stinky odor. So Sun was extremely wary of anything that might in any measurable way impact performance. So in this perspective, it made sense to make disabling assertion-testing the default.

Another reason to disable by default might have been related to the fact that, in adding the new assertion facility, Sun had hijacked the word assert. This was not a previously reserved keyword, and required one of the few changes ever made to the Java language. The method name assert had been used by many libraries and by many developers in their own code. For some discussion of this historical transition, read this old documentation, Programming With Assertions.

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