Most issues in software fall into this category, though. The issue with Java’s null is that it’s not type safe. The language is generally a strongly typed language, except in the case of null. And until Value Types land, there is no way to express nullability to the compiler.
The arguments you make aren’t all that different than the undefined behavior arguments with C. “Just follow these simple rules and you’ll avoid all issues”, a compiler should do that for you IMO.
I can’t wait for Value Types in Java, at that point we can have real Option types.
No downvote, but GP post conflates "how code SHOULD be written" with "how existing code was written" in my opinion. Same with one of the earlier comments about "idiomatic C++ does bounds checking." I've seen plenty of NPEs in real, working Java.
If Mozilla isn't managing to write idiomatic C++, I don't hold out much hope for myself either.
> “Just follow these simple rules and you’ll avoid all issues”, a compiler should do that for you IMO.
This was one thing I really liked about Kotlin vs Java. It's nice that my IDE can do the work of generating getters/setters on a POJO for me, but it's not nice that the language requires me to fill my source code with that noise. To a first approximation, any task rote enough the computer could do it for me, it should not ask me to do.
See also: static languages that don't offer type inference.
For params and return values you still can’t know for sure, and in all these cases it -could- be null. But yes, making all fields and variables that are Optional would help as a coding practice, except of course where you need to reassign the value in the Optional, as there is no “set” on the type.
Also there are plenty of domains where Java or C++ aren't even taken into consideration, in spite of decades of effort.
Just to cite Microsoft's recent security recommendation out of Blue Hat conference, regarding their own software, "use a mix of C#, Rust and constrained C++".
That said, "write good tests" is impossible. You can write as many tests as you want, you can make sure those loops loop or don't, and those ifs if or don't, but you cannot write "good" tests. Tests will always miss some corner case, some input, some unexpected locale variable.
https://www.infoq.com/presentations/Null-References-The-Bill...
More nuanced ones can often be caught by using all args constructors and requiring the constructor values with Objects.requiresNonNull() or similar. Using spring? Don't use field or setter injection, always constructor so the above applies as well. Making the state of your objects largely immutable means their state is more consistent and what is null and when becomes a lot less surprising.
Lastly, write good tests. If you're exhausting the behavior of your system with tests, these things are much less likely to surprise you later.
NPEs are definitely a problem with Java, but they're a very avoidable one as well.
Edit: I don't understand the downvotes. The parent said they're a huge deal and I'm disagreeing because I think they're relatively simple to avoid?