Catching invalid method arguments using assert

Viewed 47

I am slightly confused regarding assert.

I have a constructor for a Circular array where the capacity of the array obviously could not be negative as a negative length for an array is invalid. I am aware I could set the value myself if it is invald or throw an exception but I've also seen assert used to prevent invalid input (specifically in C) so I tried following.

Constructor (excluding all the unnecessary parameters that also is initialized): Note, Message is simply a class that holds a string.

    public CircularArray(int capacity)
{
    assert capacity > 0 : "Array capacity violated, precondition argument > 0";
    elements = new Message[capacity];
}

and if I run it with -ea the assertion is indeed displayed however I still recieve what seems to be an error or trying to initialize an array with an invalid length. Is this how it's supposed to look or do I have to something additional?

Also, since assertions are turned off by default, would it be better to instead throw and exception as follows:

throw new IndexOutOfBoundsException();

To clarify, the terminal output yields:

Exception in thread "main" java.lang.AssertionError: Array capacity violated, precondition argument > 0

at CircularArray.<init>(CircularArray.java:19)

at CircularArray.main(CircularArray.java:98)

Maybe this is the correct output but it felt a bit strange that it clarified what where the errors are generated by specifying what lines of code.

2 Answers

You wrote

Also, since assertions are turned off by default, would it be better to instead throw and exception as follows:

throw new IndexOutOfBoundsException();

Yes, that’s precisely what the guidelines say:

  • Do not use assertions for argument checking in public methods.

    Argument checking is typically part of the published specifications (or contract) of a method, and these specifications must be obeyed whether assertions are enabled or disabled. Another problem with using assertions for argument checking is that erroneous arguments should result in an appropriate runtime exception (such as IllegalArgumentException, IndexOutOfBoundsException, or NullPointerException). An assertion failure will not throw an appropriate exception.

But the most appropriate exception would be IllegalArgumentException in your case, as the specified number is not an index. This is what standard collection constructors, e.g. ArrayList(int initialCapacity), also use. Note that it is uses an exception message like "Illegal Capacity: " + initialCapacity, including the actual illegal value, which you might consider as well.

The assert statement is for checking invariants which should be fulfilled by application logic anyway, so that turning the checks off should make no difference, at least in theory (they may make a difference in practice due to bugs, which is what these checks are all about).

This is how assert works :

assert condition : expression

When it fails, it passes the expression as parameter of the AssertionException and throws it.

Since assertion is turned off by default it would be better to use a different handling to have more flexibility on the target platforms where it's supposed to run on.

example using IndexOutOfBoundsException :

public CircularArray(int capacity) {
  if (capicity <= 0) {
    throw new IndexOutOfBoundsException("Array capacity violated, precondition argument > 0");
  }
  elements = new Message[capacity];
}

If you feel like IndexOutOfBoundsException is not the right Exception to be thrown you can replace it by another one or even create a custom one :

    public class CircularArrayInitialisationException extends Exception {

      public CircularArrayInitialisationException (String message, Throwable cause, ErrorCode code) {
          super(message, cause);
          this.code = code;
      }
      ...
  }
Related