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");
    }
    ...
}
1
  • I prefer a simple obj.hashCode() instead ;-)
    – Marco
    Jan 12, 2019 at 9:58

6 Answers 6

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) :-)

4
  • Ah, I forgot about assertions being removed! Great answer. I'll wait a bit to see if anything else comes in, then accept it :)
    – Daenyth
    Feb 27, 2012 at 19:17
  • 3
    Note that there is no flag that removes assertions at compile time (although they may be removed via conditional compliation). Assertions are disabled at runtime by default (I think the JVM treats them as NOOP), but can be enabled via java -ea and programmatically. @Jalayn I think having assertions in production code is perfectly valid, as they are useful for debugging in the field Jan 24, 2014 at 7:30
  • 2
    @Jalayn, -1. The compiler does not remove assertion code. Even though they will not be run unless you do cmd java -ea.
    – Pacerier
    Aug 26, 2014 at 16:15
  • 6
    no need for the Spring framework when you can use Objects.requreNonNull Oct 10, 2017 at 18:12
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".

4
  • 1
    This information is really helpful, but I'm accepting Jalayn's since it points out how I could potentially introduce a bug with the assert method.
    – Daenyth
    Feb 27, 2012 at 21:43
  • 5
    excellent point "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." Sep 19, 2013 at 12:41
  • True, but this assumes OP is writing a library. If their code is just for internal use an assert is acceptable.
    – user949300
    Apr 24, 2018 at 4:12
  • What if your language (e.g. C) doesn't support throwing an exception? Aug 26, 2023 at 19:56
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.

5
  • Thanks for pointing out Objects.requireNonNull(), which was new to me. Do you know if there's a similar "requireTrue()" or "requireEqual()" method anywhere? Nothing against Spring's Assert but not everybody is using that.
    – user949300
    Oct 11, 2017 at 0:01
  • @user949300 Objects.requireNonNull() is for argument validation. If an argument is required to be true or equal to something, then the argument is pointless. For error cases other than illegal arguments, you should throw an Exception that more accurately describes the error. There is also JUnit Assert but that is for tests. Oct 11, 2017 at 0:15
  • I was thinking more like, say for a square root function, Objects.requireTrue(x >= 0.0); , or for some hash, Objects.requireEquals(hash.length == 256)
    – user949300
    Nov 19, 2017 at 20:00
  • Which @Nonnull I have to use ? javax.validation.constraints.NotNull ?
    – Aguid
    Mar 26, 2018 at 8:39
  • In 2024, use JSpecify, which is kind of becoming a standard.
    – koppor
    Mar 16 at 23:59
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.

3
  • 5
    Assertions were around about 40 years before JUnit - ask a C programmer about ASSERT macros. Feb 22, 2013 at 22:04
  • 4
    this question is not about c; its about Java. So i have replied in context of Java.
    – rai.skumar
    Feb 23, 2013 at 5:43
  • Do not confuse assert (the reserved keyword) vs Assert (the JUnit class) they are both used to perform a check on a variable but beyond that they are two very different things and behaves very differently.
    – Newtopian
    Oct 11, 2017 at 22:01
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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.