Why does requireNotNull throw an IllegalArgumentException?

The requireNotNull function throws an IllegalArgumentException instead of the more precise NullPointerException:

> requireNotNull(null)
java.lang.IllegalArgumentException: Required value was null.

Josh Bloch suggests in “Effective Java” to use the most precise Exception available, what is a NullPointerException in this case (and exactly this case in the book).

Why does Kotlin treat it differently? Shouldn’t it be changed?

1 Like

I think the reasoning is this. A Null pointer exception gets thrown when you try to access a field of a null object like null.someValue. The require functions in Kotlin are designed to check that the arguments passed to a function are valid. Therefor an argument exception is the right exception. The argument passed is invalid because it is null. Kotlin never tries to access the value behind the null reference and that is why this does not throw a NullPointerException.
At least that’s what I would think the reason is. Another reason could be the fact, that NullPointerExceptions in Kotlin normally mean that there is a serious error. Kotlin only uses them if you use null!! or if you actually try to dereference a null reference (which can happen in constructors or in case of serialization I think). Basically a NullPointer in Kotlin means that either you have done something you shouldn’t with (!!) or some java code you called failed.

PS: If you are using requireNotNull to do some asserting or checking the state of an object you should use assert/check instead. As I said above require is used for checking the validity of arguments passed to a function, assert is assert and check is used to test the validity of the current state of an object (e.g this function can only be called after some state has been calculated).

Interesting question. Was about to go and post it today but found that it was already asked in 2018 here. Meanwhile I did not find any decent answer regarding this Kotlin’s design decision for requireNotNull precondition function.

I will also share my observation: Besides what Joshua Bloch explicitly says in his book (he says that NPE would be more precise in this case), the Java’s java.util.Objects#requireNonNull also throws NPE. And lombok.NonNull also throws NPE (but it’s configurable in Lombok).
So there are 2-3 serious arguments for expecting kotlin.requireNotNull precondition function to throw NPE too.

On the other hand, If I compare JavaDoc for NPE and IllegalArumentException:

NPE: Thrown when an application attempts to use null in a case where an object is required

IllegalArumentException: Thrown to indicate that a method has been passed an illegal or inappropriate argument

From exceptions description it looks like IllegalArumentException is more appropriate in case when you explicitly check the input for null instead of unexpectedly attempt to dereference null value. So, no idea why Joshua Bloch suggests using NPE. I could agree with him only if I had exception names with no JavaDoc.

I also tried to check opinions on StackOverflow, there are different ones (1,2,3) and still I do not know for sure which one should I use in case when I explicitly validate the input for null :man_shrugging:t2:

Ohh, interesting question. I think depending on the perspective, we can say NPE is more specific or that IAE is more specific.

From the perspective of the line where the error occurred, IAE is just a generic error with invalid argument and NPE says what is wrong with this argument. But from the perspective of a function caller, NPE is just a generic problem somewhere inside the function and IAE says specifically that the problem was with passed arguments. So it is like 5xx vs 4xx error in HTTP. On the other hand, IAE is unchecked, so we don’t know whether it was thrown because we misused the function (4xx) or the function called another function passing wrong args (5xx).

For me IllegalArumentException makes more sense in such cases, but I think it’s a matter of taste.

Anyway, I think in Kotlin it is even more simple than that. We have two families of check functions: require* throwing IllegalArumentException and check* throwing IllegalStateException. It would be inconsistent if require() would throw IllegalArumentException, check() would throw IllegalStateException, but requireNotNull() or checkNotNull() (because they would be the same) would throw NullPointerException.

3 Likes

Good points. Actually to me IAE also makes more sense (according to what JavaDoc says). But I am confused with java.util.Objects#requireNonNull, Joshua Bloch and Lombok’s defaults :smiley:

Java’s requireNotNull and Lomboks’ NotNull are not good comparisons because they are standalone. Kotlin has require(), which is meant to test that function arguments are correct, which has an override for the null case because of contracts. requireNotNull is a specific case of require, which means that an argument is invalid.

Same case with check and checkNotNull.