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,077
  • 3
  • 31
  • 46

6 Answers6

142

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,789
  • 4
  • 39
  • 58
  • 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 '12 at 19:17
  • 3
    Note that there is no flag that removes assertions at compile time (although they may be removed via [conditional compliation](http://docs.oracle.com/javase/specs/jls/se7/html/jls-13.html#d5e15644)). 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](http://docs.oracle.com/javase/7/docs/technotes/guides/language/assert.html#design-faq-general) – Justin Muller Jan 24 '14 at 07: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 '14 at 16:15
  • 6
    no need for the Spring framework when you can use `Objects.requreNonNull` – cambunctious Oct 10 '17 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".

Sergey Kalinichenko
  • 17,393
  • 4
  • 57
  • 73
  • 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 '12 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." – Asim Ghaffar Sep 19 '13 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 '18 at 04:12
  • What if your language (e.g. C) doesn't support throwing an exception? – Mehdi Charife Aug 26 '23 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.

cambunctious
  • 250
  • 2
  • 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 '17 at 00: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. – cambunctious Oct 11 '17 at 00: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 '17 at 20:00
  • Which @Nonnull I have to use ? javax.validation.constraints.NotNull ? – Aguid Mar 26 '18 at 08:39
  • I would use the [Eclipse JDT annotations](https://help.eclipse.org/luna/index.jsp?topic=%2Forg.eclipse.jdt.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fjdt%2Fannotation%2FNonNull.html), because they are made by clever guys :). Documentation: https://help.eclipse.org/neon/index.jsp?topic=%2Forg.eclipse.jdt.doc.user%2Ftasks%2Ftask-using_null_annotations.htm - You can also configure IntelliJ to use them. – koppor Jul 09 '18 at 21:29
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.

rai.skumar
  • 202
  • 2
  • 7
  • 5
    Assertions were around about 40 years before JUnit - ask a C programmer about ASSERT macros. – JBRWilkinson Feb 22 '13 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 '13 at 05: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 '17 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

kensai
  • 161
  • 2
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
  • 1
  • 5