Concepts / Debugging Java Programs with the Command Line

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.

  • Programming

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.

java
Notes on the code
  • 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?

  • The program stops with an AssertionError because x is negative

  • The program prints Done and the assertion has no visible effect

  • The program refuses to compile

Reveal answer
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

Definition

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.

assertkeyword that starts thecheckx > 0boolean condition, alwaysrequired:separator, only with amessagex must be positiveoptional error message textchecksoptional partbecomes the error text
What does each part of an assert statement contribute to the AssertionError when the condition is false?

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.

java
Notes on the code
  • 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.

Reach assertstatement is next to runAssertions enabled?set when java startsEvaluate conditionordinary boolean checkCondition true?true or falseNext statementprogram continues normallyStatement has noeffectmoves to the next statementThrow AssertionErrorcarries the message if onewas givenProgram haltsusually crashesnoyestruefalse
When an assert condition is true, does execution continue normally, and when it is false with assertions enabled, where does control go?

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

Worked example

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?

  1. 1
    Evaluate the condition

    The condition is x > 0. With x equal to -3, the expression is false.

  2. 2
    Check whether assertions are enabled

    The run includes the -enableassertions option, so the assertion is checked rather than skipped.

  3. 3
    Throw the error

    Because the condition is false and assertions are enabled, Java throws an AssertionError. The string x must be positive becomes its message.

  4. 4
    Notice what is skipped

    The println line after the assertion never runs, because the error stopped the program before it.

Result

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.

java
Notes on the code
  • 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
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)
AspectRun without -enableassertionsRun with -enableassertions
Assert statement with a true conditionIgnored, program continuesChecked, program continues
Assert statement with a false conditionIgnored, program continuesThrows AssertionError and halts
Condition evaluated at run timeNo, the statement behaves as emptyYes
Error message usedNot applicableBecomes 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.

Best practice

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 like

    Running java Demo and wondering why the program prints Done despite x being -3.

    Why it fails

    Assertions are disabled by default at launch. A disabled assertion is treated as an empty statement, so its condition is never checked.

    Do this instead

    Add -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 fails

    The source states that a disabled assertion behaves as an empty statement and the condition is not evaluated.

    Do this instead

    Do 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 like

    assert x > 0; when the error only shows that an assertion failed with no detail.

    Why it fails

    Without an error message, the AssertionError carries no custom text describing the broken expectation.

    Do this instead

    Add 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 fails

    The source says the method depends on the programming environment, and an IDE provides its own settings.

    Do this instead

    Look up how your IDE enables assertions instead of assuming the command line option applies there.

Practice: Predict the Launch Result

EASY

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.
MEDIUM

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 AssertionError when 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.