简体   繁体   中英

Why can't we use assertion for public methods?

Why can't we use assertion for public methods?

I have read somewhere

"An assert is inappropriate in public methods because the method guarantees that it will always enforce the argument checks. A public method 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 ".

So, wont it applicable for private method too?
I didn't understand the above statement clearly

The important distinction is whether you believe an incorrect value is the result of

a) A programming bug which should be fixed in code.

b) An input error which cannot be prevented in code and instead need to be handled at runtime.

For the first case, you should use an assert, as the program code will need to be fixed. If its the later case, you should use an appropriate Runtime or check exception.


IMHO assertions are for detecting programming errors and not user/external inputs. Perhaps the author is confusing public methods as an external input when you will have public method which are not called by an external input.

I would use assertions to check arguments to detect programming errors. IMHO this is often the best use for them. Private method by comparison should only be called by code in the same class and you should expect them to be well unit tests and have limited possible access/usages.

I find that you are far more likely to have programming error via public interfaces because different people make different assumptions (assertions are a good way to document and check assumptions) Internal checks are not as useful as you would expect the same programmer to have access to the internal code if not having written the whole internal code base.

Assertions should not be used for checking arguments in public methods for the following reasons:

  • assertions can be disabled and argument checks should never be disabled as they are part of the method's contract with its callers
  • assertion failures do not throw an appropriate exception for invalid arguments.

Example:

    /**
     * @throws ArithmeticException if divisor is zero
     */ 
    public void int divide(int divisor) {
        if (divisor == 0) {
            throw new ArithmeticException("Cannot divide by zero");
        }
        ...
    }

If you used an assertion here it could be turned off, and it would throw an AssertionFailedException , which is unhelpful and uninformative.

As it stands, the sentence you quoted is nonsense, I beleive.

To be sure, assert is not for validation of parameters.

But in every non-trivial program there are (or should be) a number of invariants, and this is the place where assertions may come in handy. If you can express the invariant in an assertion, please do so, no matter if the method is public or not.

Then, one of the following will happen:

a) everything is fine.
b) At runtime, the program fails with a non fulfilled assertion. If the assertion is correct, then the invariant is violated and you have the opportunity to find out why and fix the bug (or rethink your design).

There's nothing at all wrong in using an assertion in a public method. They could be used to check that certain invariants (things you believe to be true), about the object or class that you're calling the method of - are in fact true.

For example you could use an assertion as I have done, in the public build() method of a builder, to make sure that the builder was initialized correctly by my own internal code in that class (as I have a number of overloaded constructors for it).

But what you should NEVER do, is use assertions for checking the ARGUMENTS of public methods. An important distinction. I think the other answers here have explained the reasons clearly enough already so I'm not going to repeat anything.

In general it seems sound. Although there are some occasion where this might be useful.

Consider that we might want to perform a database update operation for an element we know exist. Then it might be useful to see if the routine succeeded, eg, :

public void update(Object o) {
   int nUpdatedObjects = dao.update(o);
   assert(nUpdatedObjects == 1)
}

In this case it serves to validate the dao layer using the fail fast principle .

Assertions are for debugging; public methods generally shouldn't validate things by debug assertions, but by doing proper argument checks and throwing the appropriate exceptions. It's okay to use it if you want to validate internal object state, but not to validate parameters.

I give a response that is not exactly on the point. Of course you can use assert in public methods (or wherever you like).

The point is more on what you should do or not. I myself perfectly understand other people's response about when you should or shouldn't use assertion.

But I must admit that I NEVER use assertions, and that I rarely if ever see assertions in code. I worked only for a few years, but on the 4 totally different companies I worked for, there were no assertions in code. Be it the more than 10 millions line of code web application to book flights, a spacecraft control center, a software to manage hypermarket or a bug tracker. None of them used asserts. All companies had different needs and methods. None used asserts.

For me the reason is simple. People here say that assertions are for debugging. That's fine. And that you can deactivate them for improved speed. That fine too... At first. The more complex the program, the more you pass time debugging. And some bugs, even with 100% code coverage, even with extensive integration and validation testing, you'll find them only in production. Simply because your users end up using your application more than you. And they will not use it the same way as you.

It's funny because in production logs, we keep seeing stacktraces from code like this :

catch (MyException e) {
  logger.war("This should never happen",e);
}

What that means is that you never know what could occur in production.

And that if you have the opportunity to make a check, do it. Of course the log comment is more funny than useful here and it would be better to let the exception popup.

In all cases don't make it an assertion that will be disabled in production. Because it will be useless. Make it normal code that raises an exception. Ensure it is logged if appropriate. Ensure that an error will be displayed on the UI. And ensure you be able to get the exception and the logs to investigate.

What is important is that one day or the other, some user will do things that make the warning popup. Be it because of a badly written code or anything, you'll see it. And that means that instead of spending 2 days finding why in hell the program has this strange behavior, you'll be able to use the full stacktrace at a starting point and correct the problem in 2 hours.

A check with a disabled assert is the same as no check at all. It is code you must write, read and maintain... For nothing. I understand the whole performance argument where assertions in production slow things down. Yes in some few case, there is a performance problem. In most case, you'll gain almost nothing anyway and lost precious hints.

This is probably the original source, from the Java SE guide "Programming with assertions."

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.

This does not proscribe assertions in public methods. It proscribes them only for checking public-method arguments.

Assertions test invariants. A class controls the actual arguments sent to its private methods, and can guarantee invariants. A class does not control the actual arguments sent to public methods, and should throw exceptions if preconditions are violated, even if assertions are turned off.

More details about when to use assertions are here .

Public methods can be called by anyone and there is no control on what can be passed as argument values.

If suppose in the public method we have validated the input argument values using assertions then there is a possibility that these checks(validations) may not happen(or execute) if the assertions are disabled and we would get undesirable results from the method execution.To avoid such undesirable results we should not use assertions to validate public method argument values.

Now the question that may arise in your mind is why use assertions to validate private method argument values?

Well,the reason is that the private methods can be called from within the class it is defined(Either from instance method or from static main method).The developer of the class infact knows everything about the private method- what it does, how to call it and what parameter values to pass.Hence private method argument values can be safely validated using assertions.

The idea is that you don't know who will use your public method. So you must defend yourself against improper usage with normal checks.

Private methods on the other hand should be used solely by developers on your current team, so checks are not (that) mandatory (but still recommended IMHO).

So for checking argument validity on private methods asserts should be enough.

This prohibition only applies to public interfaces.

From http://download.oracle.com/javase/6/docs/technotes/guides/language/assert.html#preconditions :

By convention, preconditions on public methods are enforced by explicit checks that throw particular, specified exceptions.

Basically, the convention is that public interfaces are guaranteeing to check preconditions and to throw specific exceptions instead of AssertionError.

For all other cases, assertions are very valuable and are a cornerstone for "programming by contract." See http://java.sun.com/developer/technicalArticles/JavaLP/assertions for a good introduction.

  1. Java has unchecked exceptions for a reason -- these are plenty of catastrophic failures that should not generally be caught. Any memory allocation can throw OutOfMemoryError. A failed assertion (a bug in client's code that supplied an invalid argument to our API) is no less catastrophic.

  2. It is true that assertions can be turned off. This should never be done, though. Just do not do it. If you are afarid that someone who is running your code will turn off assertions, you can always create a trivial assertion class of your own that cannot be turned off. The principle of using assertions is unchanged.

  3. The only things about assertions you should consider is the performance contract on your interfaces. Note that this could also be an "implicit" contract (ie when an obvious implementation should be very quick, taking a minute is outside of the implied performance contract). So make sure that verifying your assertions acceptable under performance contract.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM