116

In Java, which is more highly recommended, and why? Both types will throw exceptions, so in that regard handling them is the same. assert is slightly shorter, but I'm not sure how much that matters.

public void doStuff(Object obj) {
    assert obj != null;
    ...
}

vs

public void doStuff(Object obj) {
    if (obj == null) {
        throw new IllegalArgumentException("object was null");
    }
    ...
}
Daenyth
  • 8,147

6 Answers6

143

BEWARE!

Assertions are removed at runtime unless you explicitly specify to "enable assertions" when compiling your code. Java Assertions are not to be used on production code and should be restricted to private methods (see Exception vs Assertion), since private methods are expected to be known and used only by the developers. Also assert will throw AssertionError which extends Error not Exception, and which normally indicates you have a very abnormal error (like "OutOfMemoryError" which is hard to recover from, isn't it?) you are not expected to be able to treat.

Remove the "enable assertions" flag, and check with a debugger and you'll see that you will not step on the IllegalArgumentException throw call... since this code has not been compiled (again, when "ea" is removed)

It is better to use the second construction for public/protected methods, and if you want something that is done in one line of code, there is at least one way that I know of. I personally use the Spring Framework's Assert class that has a few methods for checking arguments and that throw "IllegalArgumentException" on failure. Basically, what you do is:

Assert.notNull(obj, "object was null");

... Which will in fact execute exactly the same code you wrote in your second example. There are a few other useful methods such as hasText, hasLength in there.

I don't like writing more code than necessary, so I'm happy when I reduce the number of written lines by 2 (2 lines > 1 line) :-)

Jalayn
  • 9,827
53

You need to use an exception. Using an assertion would be a misuse of the feature.

Unchecked exceptions are designed to detect programming errors of the users of your library, while assertions are designed to detect errors in your own logic. These are separate issues that should not be mixed.

For example, an assertion

assert myConnection.isConnected();

means "I know that each code path leading to this assertion ensures that myConnection is connected; if the code above failed to get a valid connection, it should have thrown an exception or return before reaching this point."

On the other hand, a check

if (!myConnection.isConnected()) {
    throw new IllegalArgumentException("connection is not established");
}

means that "Calling my library without establishing a connection is a programming error".

15

If you are writing a function that does not allow null as a valid parameter value, you should add the @Nonnull annotation to the signature and use Objects.requireNonNull to check if the argument is null and throw a NullPointerException if it is. The @Nonnull annotation is for documentation and will provide helpful warnings at compile time in some cases. It does not prevent null from being passed at runtime.

void doStuff(@Nonnull Object obj) {
    Objects.requireNonNull(obj, "obj must not be null");

    // do stuff...
}

Update: The @Nonnull annotation is not part of the Java standard library. Instead, there are numerous competing standards from third party libraries (see Which @NotNull Java annotation should I use?). That doesn't mean it's a bad idea to use it, just that it's not standard.

2

I always prefer to throw IllegalArgumentException over assertions.

Assertions are used mostly in JUnit or other testing tools, to check/assert test results. So it might give false impression to other developers that your method is a test method.

Also it makes sense to throw IllegalArgumentException when a method has been passed an illegal or inappropriate argument. This is more consistent with the Exception Handling convention followed by Java developers.

2

I don't use aserts a lot, but common approach with Lombock @NonNull: https://projectlombok.org/features/NonNull

Lombok implementation: import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;

  public NonNullExample(@NonNull Person person) {
    super("Hello");
    this.name = person.getName();
  }
}

Java version:

 import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;

  public NonNullExample(@NonNull Person person) {
    super("Hello");
    if (person == null) {
      throw new NullPointerException("person");
    }
    this.name = person.getName();
  }
}

Lombok is really quite nice library which I use everywhere

1

IMO the second one is slightly better because it brings more information and could be further extended (e.g. by extending exception class) to be even more informative, also it doesn't use negative comparison which is easier to understand.

0lukasz0
  • 241