When to use an assertion and when to use an exception
Asked Answered
T

12

135

Most of the time I will use an exception to check for a condition in my code, I wonder when it is an appropriate time to use an assertion?

For instance,

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
}

Could you indicate how an assertion fits in here? Should I use an assertion?

It seems like I never use assertions in production code and only see assertions in unit tests. I do know that in most cases, I can just use exception to do the checking like above, but I want to know appropriate way to do it "professionally".

Thalamus answered 24/12, 2009 at 10:0 Comment(0)
S
91

Assertions should be used to check something that should never happen, while an exception should be used to check something that might happen.

For example, a function might divide by 0, so an exception should be used, but an assertion could be used to check that the harddrive suddenly disappears.

An assertion would stop the program from running, but an exception would let the program continue running.

Note that if(group != null) is not an assertion, that is just a conditional.

Somatic answered 24/12, 2009 at 10:5 Comment(5)
"an assertion could be used to check that the harddrive suddenly disapears" - I'd say this is not correct: why would you want this handled during development, but not in production (when assertions are typically disabled)?Fortepiano
The comment about the hard drive is wrong. Assertions are for checking for errors in your code logic. Never, ever, use them to check something that you don't control. Remember, if an assertion fails it means that your code is wrong.Squish
@Somatic Your conditional could be replaced with an assertion like this: assert group != nullPetal
Downvoted because the hard drive example contradicts your own philosophy. Hard drives "disappearing" (from the perspective of the code) could actually happen in reality -- no matter how improbable. Like @IanGoldby says, assertions should depend purely on things controlled by your code.Scaramouch
A much better answer if posted by Gregory Pakosz, please read that post.Carbo
P
189

Out of my mind (list may be incomplete, and is too long to fit in a comment), I would say:

  • use exceptions when checking parameters passed to public or protected methods and constructors
  • use exceptions when interacting with the user or when you expect the client code to recover from an exceptional situation
  • use exceptions to address problems that might occur
  • use assertions when checking pre-conditions, post-conditions and invariants of private/internal code
  • use assertions to provide feedback to yourself or your developer team
  • use assertions when checking for things that are very unlikely to happen otherwise it means that there is a serious flaw in your application
  • use assertions to state things that you (supposedly) know to be true

In other words, exceptions address the robustness of your application while assertions address its correctness.

Assertions are designed to be cheap to write, you can use them almost everywhere and I'm using this rule of thumb: the more an assertion statement looks stupid, the more valuable it is and the more information it embeds. When debugging a program that does not behave the right way, you will surely check the more obvious failure possibilities based on your experience. Then you will check for problems that just cannot happen: this is exactly when assertions help a lot and save time.

Petrolic answered 24/12, 2009 at 10:3 Comment(3)
I like the way you phrased this: Exceptions address the robustness of your application while assertions address its correctness.Curtal
I cross posted this to my site: pempek.net/articles/2013/11/16/assertions-or-exceptionsPetrolic
And if you happen to look for a C++ custom assert library, I released github.com/gpakosz/AssertPetrolic
S
91

Assertions should be used to check something that should never happen, while an exception should be used to check something that might happen.

For example, a function might divide by 0, so an exception should be used, but an assertion could be used to check that the harddrive suddenly disappears.

An assertion would stop the program from running, but an exception would let the program continue running.

Note that if(group != null) is not an assertion, that is just a conditional.

Somatic answered 24/12, 2009 at 10:5 Comment(5)
"an assertion could be used to check that the harddrive suddenly disapears" - I'd say this is not correct: why would you want this handled during development, but not in production (when assertions are typically disabled)?Fortepiano
The comment about the hard drive is wrong. Assertions are for checking for errors in your code logic. Never, ever, use them to check something that you don't control. Remember, if an assertion fails it means that your code is wrong.Squish
@Somatic Your conditional could be replaced with an assertion like this: assert group != nullPetal
Downvoted because the hard drive example contradicts your own philosophy. Hard drives "disappearing" (from the perspective of the code) could actually happen in reality -- no matter how improbable. Like @IanGoldby says, assertions should depend purely on things controlled by your code.Scaramouch
A much better answer if posted by Gregory Pakosz, please read that post.Carbo
M
30

Remember assertions can be disabled at runtime using parameters, and are disabled by default, so don't count on them except for debugging purposes.

Also you should read the Oracle article about assert to see more cases where to use - or not to use - assert.

Mesenchyme answered 24/12, 2009 at 10:4 Comment(1)
Hue hue hue I was wondering why my code was failing in Eclipse but running fine on the command line.Brumley
S
17

As a general rule:

  • Use assertions for internal consistency checks where it doesn't matter at all if someone turns them off. (Note that the java command turns off all assertions by default.)
  • Use regular tests for any kind of checks what shouldn't be turned off. This includes defensive checks that guard against potential damage cause by bugs, and any validation data / requests / whatever provided by users or external services.

The following code from your question is bad style and potentially buggy

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

The problem is that you DON'T know that an exception means that the group was not found. It is also possible that the service() call threw an exception, or that it returned null which then caused a NullPointerException.

When you catch an "expected" exception, you should catch only the exception that you are expecting. By catching java.lang.Exception (and especially by not logging it), you are making it harder to diagnose / debug the problem, and potentially allowing the app to do more damage.

Suffer answered 24/12, 2009 at 14:50 Comment(0)
F
4

Well, back at Microsoft, the recommendation was to throw Exceptions in all APIs you make available publicly and use Asserts in all sorts of assumptions you make about code that's internal. It's a bit of a loose definition but I guess it's up to each developer to draw the line.

Regarding the use of Exceptions, as the name says, their usage should be exceptional so for the code you present above, the getGroup call should return null if no service exists. Exception should only occur if a network link goes down or something like that.

I guess the conclusion is that it's a bit left down to the development team for each application to define the boundaries of assert vs exceptions.

Forwards answered 24/12, 2009 at 10:6 Comment(2)
IMHO, the problem with that kind of recommendation is that it's fine as long as the boundary between the public and private parts of an API is pretty fixed. If you're developing new code then that boundary is often pretty fluid...Rhombus
Yes, you're right. It's a guideline but at the end of the day it's left out to the programmers sensitivity. I don't think there's a ultimate defining line for these so I guess you just go with what you think it's right from reading loads of different code.Forwards
F
3

According to this doc http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#design-faq-general, "The assert statement is appropriate for nonpublic precondition, postcondition and class invariant checking. Public precondition checking should still be performed by checks inside methods that result in particular, documented exceptions, such as IllegalArgumentException and IllegalStateException."

If you want to know more about precondition, postcondition and class invariant, check this doc: http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#usage-conditions. It also contains with examples of assertions usage.

Fleisig answered 22/10, 2012 at 21:31 Comment(0)
A
1

Testing for null will only catch nulls causing problems, whereas a try/catch as you have it will catch any error.

Broadly, try/catch is safer, but slightly slower, and you have to be careful that you catch all the kinds of error that may occur. So I would say use try/catch - one day the getGroup code may change, and you just might need that bigger net.

Ammonium answered 24/12, 2009 at 10:4 Comment(0)
G
1

I confess I'm a little confused by your question. When an assertion condition is not met, an exception is thrown. Confusingly this is called AssertionError. Note that it's unchecked, like (for example) IllegalArgumentException which is thrown in very similar circumstances.

So using assertions in Java

  1. is a more concise means of writing a condition/throw block
  2. permits you to turn these checks on/off via JVM parameters. Normally I would leave these checks on all the time, unless they impact runtime performance or have a similar penalty.
Gene answered 24/12, 2009 at 10:41 Comment(3)
AssertionError is a subclass of Error not RuntimeException.Suffer
Ah. Of course. I was thinking of checked/unchecked. Now correctedGene
It explains what assertions are (from a controversial point of view), but not when to use them exactly.Solipsism
M
1

Unfortunately asserts can be disabled. When in production you need all the help you can get when tracking down something unforeseen, so asserts disqualify themselves.

Marciemarcile answered 24/12, 2009 at 14:25 Comment(0)
B
1

You can use this simple difference in mind while their usage. Exceptions will be used for checking expected and unexpected errors called checked and unchecked error while assertion is used mainly for debugging purposes at the run time to see whether the assumptions are validated or not.

Bowyer answered 11/6, 2012 at 9:37 Comment(0)
R
0

See section 6.1.2 (Assertions vs. other error code) of Sun's documentation at the following link.

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

This document gives the best advice I've seen on when to use assertions. Quoting from the document:

"A good rule of thumb is that you should use an assertion for exceptional cases that you would like to forget about. An assertion is the quickest way to deal with, and forget, a condition or state that you don’t expect to have to deal with."

Rani answered 12/7, 2012 at 4:35 Comment(0)
I
0

I’m not experienced with Java asserts but I think the answer here naturally follows from what Java asserts are:

  1. Code that is only run if enabled
  2. Disabled by default

Thus we can surmise that assertions should never be used to implement application logic: it should only be used as optional (because of the on/off feature) sanity checks/explicit assumptions. The correctness of your app (modulo bugs!) cannot depend on a runtime flag which is turned off by default.

So only use assertions to check internal assumptions (your own code only, not things that are out of your control like user input). But on the other hand you might sometimes want to use exceptions to check your assumptions; if you want to always check a certain assumption then you don’t need the on/off feature that assertions provide.

For the task of checking assumptions, it seems that assertions excel when:

  1. The check might be costly so you want the option of disabling it

  2. Using if-or-throw would be too much “noise” but you can bear the cost of one little assert <expr>

  3. You want to leave a little comment which merely states something like:

    // NOTE we KNOW that `x` is not null!
    x.doWork();
    

    Then the Java folks say that you should always replace that line with:

    assert x != null;
    x.doWork();
    

    Or (in my opinion) if you prefer:

    if (x == null) {
        throw new IllegalStateException("shouldn’t be null");
    }
    x.doWork();
    

Things that follow from these principles

I think we can immediately expand on related principles (sibling answer) by using this “optional” principle (my gloss in cursive):

  • use exceptions when checking parameters passed to public or protected methods and constructors
    • Because you are checking things outside your code: code coming into your module
  • use exceptions when interacting with the user or when you expect the client code to recover from an exceptional situation
    • Because the input is from the user and has nothing to do with your code. Also assertions are not really something you are supposed to recover from.(†1)
  • use exceptions to address problems that might occur
    • I.e. errors that happen as a matter of course: not bugs in your code
  • use assertions when checking pre-conditions, post-conditions and invariants of private/internal code
    • Because it’s your own code: problems inside your own code are self-caused
  • use assertions to provide feedback to yourself or your developer team
    • Bugs are for developers to deal with
  • use assertions when checking for things that are very unlikely to happen otherwise it means that there is a serious flaw in your application
    • Key word “serious flaw in your application”
  • use assertions to state things that you (supposedly) know to be true
    • Checking assumptions

Notes

  1. I think this is a general opinion. See also (my bold):

    Why is AssertionError a subclass of Error rather than RuntimeException?
    This issue was controversial. The expert group discussed it at length, and came to the conclusion that Error was more appropriate to discourage programmers from attempting to recover from assertion failures.

Interchange answered 6/1, 2023 at 23:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.