“The null-safety compilation failure will occur when attempting to construct the Kotlin class from within Kotlin code. When the Kotlin class is constructed from another language such as Java or Groovy anIllegalArgumentExceptionwill be thrown at runtime. In this sense the Kotlin creators’ argument of avoiding NPEs does not pragmatically hold true as theNullPointerExceptionhas simply been replaced by anIllegalArgumentException.”
I wrote the above statement the other day as part of a potential new book I am working on. However, I am not quite happy with it and I think it could sound a bit harsh or might not be quite correct either. I believe it can do with community feedback and with some more discusion, which I would be happy to accommodate, include and credit.
The argument has always been “you can avoid NPEs at compile time if you write Kotlin code”. Of course, if you use Kotlin code from code written in other languages, then there is no way to guarantee the absence of NPEs at compile time, because Kotlin is not involved in the process of compiling that other code.
Whether this argument pragmatically holds true or not depends on the kind of system you’re writing.
Another important point is when exactly the exception happens. In the Java case, the exception usually happens at some random place when you’re trying to use the object, where it’s not always clear where the object came from (it may have been passed through multiple calls, stored in collections, etc). In the case of Kotlin, there is a clear boundary where the validation happens - the public API of classes written in Kotlin. This makes it much easier to diagnose the errors when they do happen. And once you’re inside that boundary, you can be sure that the nullability contract is followed.
In addition to what Dmitry just said: Kotlin annotates all method parameters and return values automatically with the org.jetbrains.annotations.NotNull annotation. These annotations can (and in IntelliJ are) used from the Java side as well.
That means, writing Kotlin code provides the following advantages:
all methods automatically have Nullability annotations. You can use them in Java Code as well (without the visual clutter)
Nullability checks are generated by the compiler. They are enforced at the earliest possible moment (and not at the time of access, which might be at some other far away random place). Again without the visual clutter of the those checks.
Kotlin has the chance to establish a clearly defined model of what nullability means. This is really hard to do in Java because Eclipse, FindBugs and IDEA have different opinions what the @NotNull, @NonNull and @Nullable annotations mean (e.g. for inherited classes, field declarations)
You do not have the visual clutter of the Java 8 Optional class
The last point is debatable, though. The more Java APIs include the use of Optional the more alien they will feel in Kotlin.