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
.