Debugging Java Programs with the Command Line
An assert statement checks a condition; if the condition is false while assertions are enabled, Java throws an AssertionError.
Predicting an Assertion Outcome
Suppose you are debugging a program and you believe that some value must always be positive at a certain point. You could print the value and check it by eye, but that is slow and easy to forget. Java offers a more direct tool: a statement that states the condition you expect to hold and reports a problem if it does not. That statement is called an assertion. This article explains how to write assertions, what Java does when they pass or fail, and how the command line decides whether they are checked at all.
- The assert line states that x should be greater than 0.
- The colon and the string after it form the optional error message.
- The value of x is -3, so the condition is false.
What do you think happens?
The class above is compiled and then run with the plain command java Demo, with no extra option. What do you think happens?
Reveal answer
The program prints Done and the assertion has no visible effect.
Assertions are switched on at run time, not at compile time. Without the -enableassertions option, a disabled assertion behaves as an empty statement, so the false condition is never checked and execution moves on to the println line.
What an Assert Statement Checks
An assert statement checks a condition. If the condition is false while assertions are enabled, Java throws an AssertionError.
The check itself is ordinary boolean evaluation. The condition is an expression that produces true or false, just like the condition in an if statement. The important difference is what happens next. An assertion is not a branch that the program chooses to take. It is a statement that says the condition is expected to hold, and it reports a problem if that expectation turns out to be wrong.
The reason for this design is the debugging workflow. Java assertions are meant to be switched on while you are hunting for bugs and switched off for normal use. When you are debugging, a failing assertion points you to the exact place where one of your assumptions broke down. This is far more useful than a wrong result that only appears much later in the program.
Syntax With and Without a Message
Java has two forms of the assertion statement. The first takes only a condition, written as assert condition; The second adds a colon and an error message, written as assert condition : error-message; The condition is always required. The error message is optional.
The error message matters when the assertion fails. According to the source, if the statement includes an error message, that string becomes the message of the AssertionError. Without it, the error carries no custom text. For that reason, a message that describes the expected condition is a good habit for any assertion you think might fail in the future.
- The first line uses the condition alone.
- The second line adds a colon and a message that will appear in the
AssertionError.
Tracing the Two Outcomes
When execution reaches an enabled assert statement, Java evaluates the condition. The diagram below follows the two possible paths. If the result is true, nothing visible happens and the program moves on to the next statement. If the result is false, the program does not quietly continue. It throws the error and, in the usual case, crashes.
Read the diagram from the top. A disabled assertion takes the left path and is treated as an empty statement. An enabled assertion takes the right path, where the condition decides everything. A true condition returns control to the normal flow. A false condition sends control to the error, which halts the program.
Worked Example: A Failing Positive-Value Check
Checking whether a value is positive
The Demo class assigns x the value -3 and then asserts that x is greater than 0 with the message x must be positive. The program is run with assertions enabled. What happens?
- 1Evaluate the condition
The condition is x > 0. With x equal to -3, the expression is false.
- 2Check whether assertions are enabled
The run includes the -enableassertions option, so the assertion is checked rather than skipped.
- 3Throw the error
Because the condition is false and assertions are enabled, Java throws an
AssertionError. The string x must be positive becomes its message. - 4Notice what is skipped
The println line after the assertion never runs, because the error stopped the program before it.
The program halts with an AssertionError whose message is x must be positive, and Done is never printed.
Turning Assertions On at Launch
An assertion has no effect unless assertions are enabled when the program runs. This is what distinguishes Java from C and C++, where the source says assertions are turned on and off at compile time. In Java, the switch is at run time. The assertion is always compiled into the class file, but whether it does anything depends on how you start the program.
On the usual command line, you enable assertions by adding the option -enableassertions to the java command. The option goes between java and the class name, so the command has the form java -enableassertions ClassName. The source's example uses a class named RootFinder, which contains the main method. The same pattern applies to any class that has a main method.
- javac compiles the source, and the assertion is compiled into
Demo.class. - Running java Demo leaves assertions disabled, so the false check is ignored.
- Running java -enableassertions Demo turns the check on, so the false check throws an
AssertionError.
Output of java Demo:
Done
Output of java -enableassertions Demo:
Exception in thread "main" java.lang.AssertionError: x must be positive
(followed by a stack trace showing where the error was thrown)| Aspect | Run without -enableassertions | Run with -enableassertions |
|---|---|---|
| Assert statement with a true condition | Ignored, program continues | Checked, program continues |
| Assert statement with a false condition | Ignored, program continues | Throws AssertionError and halts |
| Condition evaluated at run time | No, the statement behaves as empty | Yes |
| Error message used | Not applicable | Becomes the AssertionError message if given |
How the same program behaves depending on the launch option
Why Disabled Assertions Cost Little
The source describes what a disabled assertion looks like at execution time. It behaves as an empty statement and has no effect. Because the condition is not evaluated in that case, there is little or no performance penalty for leaving assertions in a finished program. The same source code therefore serves two purposes, because the decision about whether to check assertions is made when the program starts.
Run debugging sessions with assertions enabled, so that any broken assumption stops the program at its source. Run the finished program normally, where the disabled assertions cost little or nothing.
Mistakes Beginners Make with Assertions
Common mistake Expecting a failing assertion to stop the program during a normal run
What it looks likeRunning java Demo and wondering why the program prints Done despite x being -3.
Why it failsAssertions are disabled by default at launch. A disabled assertion is treated as an empty statement, so its condition is never checked.
Do this insteadAdd -enableassertions to the java command while debugging, as in java -enableassertions Demo.
Common mistake Assuming the condition is still evaluated when assertions are disabled
Why it failsThe source states that a disabled assertion behaves as an empty statement and the condition is not evaluated.
Do this insteadDo not rely on an assert condition to do work your program needs. Keep required logic outside the assert statement.
Common mistake Writing an assertion with no message when the failure would be hard to interpret
What it looks likeassert x > 0; when the error only shows that an assertion failed with no detail.
Why it failsWithout an error message, the
AssertionErrorcarries no custom text describing the broken expectation.Do this insteadAdd a message that describes the expected condition: assert x > 0 : "x must be positive";
Common mistake Assuming the command line flag is the only way to enable assertions
Why it failsThe source says the method depends on the programming environment, and an IDE provides its own settings.
Do this insteadLook up how your IDE enables assertions instead of assuming the command line option applies there.
Practice: Predict the Launch Result
Using the Demo class from earlier, change the line int x = -3; to int x = 5;. Predict the output of java Demo and of java -enableassertions Demo before running either command. Then explain in one or two sentences why the two results match or differ.
Hints
- Check whether the condition x > 0 is true or false when x is 5.
- A true condition lets execution continue normally, whether or not assertions are enabled.
- The launch option only changes what happens when the condition is false.
Write an assert statement that checks that a variable count is not negative, and give it an error message that a reader could use to understand the failure. Then write the exact java command you would use to run the class with assertions enabled.
Hints
- Use the two-part form: assert condition : message;
- The -enableassertions option goes between java and the class name.
Key Takeaways
- An assert statement evaluates a boolean condition; a true condition lets execution continue, while a false condition throws an
AssertionErrorwhen assertions are enabled. - The syntax is assert condition; or assert condition : message; and the message, when present, becomes the text of the
AssertionError. - Assertions are enabled at run time with -enableassertions placed between java and the class name, and disabled assertions behave as empty statements.
- Because a disabled assertion's condition is not evaluated, leaving assertions in a finished program costs little or nothing, so debug with them on and run normally with them off.