That is probably responsible for more of the lost sleep in my life than any other single entity.
Various versions of "out of file descriptors" might be a close second.
Hard to predict I agree with. My experience, though, is that some ops person usually either overprovisions, or throttles, and that particular instance of "out of descriptors/sockets" goes quiet for a long time. Basically, people other than the dev team (who have conflicting priorities), can mitigate it.
Poorly written Java (like null pointer exceptions) otoh, is hard to mitigate from the outside. So it endures.
... but we'll still struggle with java.lang.NullPointerException in 2080.
If you can't have nulls, you might have a better chance of spotting the possibility of that missing data and trying to deal with it, granted, but if it happens truly unexpectedly the bug is still going to manifest itself somehow, as an NPE or otherwise.
Following all the way through, let's say there is no exception anywhere and the missing data gets all the way through to the UI.. well then that's how the bug manifests.
Is the missing data just not appearing better than a 'oops, something went wrong' error or similar in response to a 500 caused by an NPE? Depends on the application and circumstances I guess, but in general probably not. The bug exists in both cases. You can present it in better and worse ways, but the bug is that the data is not there and it should be.
The point being, not having NPE doesn't fix any problems, fundamentally. It just shifts them elsewhere. No language feature saves you from bugs.
NPE is the problem. The point of type systems with non-nullable references is that they force you to handle the null case explicitly using an Option/Maybe type by throwing a compiler error instead of an exception in production.
Nobody expects that getting rid of NPEs would get rid of bugs. It would, however, force one of the most common classes of bugs to be handled when it is cheapest to do so, rather than when the production system is on fire.
In the case where a piece of data can be missing, and that's fine, I completely agree that optional/maybe types are useful to model that explicitly and unambiguously. They let you and future maintainters know that this is the case, via the type system, at compile time.
But what I'm talking about here is genuine runtime exceptions (which NPE is in Java, of course), where the design of the system says that this piece of data cannot be missing and yet, at runtime, you encounter a case where it is missing, erroneously, because of some bug somewhere.
Types like optionals won't help you here, because you wouldn't have used them at design time anyway. The same applies to languages completely without null references.
All type systems do is formalise expectations about how data is going to look. If the real data breaks from those expectations because of some bug at runtime, the type system can't help you.
My experience is that this is the less common of the cases in a production environment (vs dev where one may be experimenting a bit more).
With checked optionals, you'll know that the code differs from the design at compile time. If a piece of data can indeed be missing you can't compile the code without considering that case explicitly.
Java (and many other languages) allows all reference types to be null, meaning you have little compiler assistance in helping prevent NPEs.
If the language differentiates between fields/results that can be null and those that cannot, and makes the caller specifically handle the null case, then that cause of NPE will longer happen.
No, but with checked unions like optionals, "not appearing" is a behavior that you explicitly chose to implement. Checked optionals force feed every opportunity to address and amend the error to the programmer. Null pointer exceptions bubble that far up either because the programmers didn't consider all the failure modes caused by implicitly nullable types or because they truly don't care. With checked exceptions, you have limited this to just the "truly doesn't care" category because the programmer is forced to consider every failure mode at every point in the call chain: "not appearing" in that case doesn't happen by mistake but by explicit choice.
Funny coincidence, by the way. I haven't been on Instagram this past month because the app instantly crashes on launch. On iOS though, and I doubt I've got anyone after me.
In fact, a few weeks ago I caught an issue where a map in Go was unexpectedly nil when it should have been full of data (missing initializer), and I caught it because the serialized data was then consumed by the client written in Swift which doesn’t have this issue. Go thought it was writing data to spec but the client immediately diagnosed it as having an unexpected null before it even tried to work with the data.
But both Java and Go are serious languages.
Who knows how long they got away with this before someone noticed "ghost tablets" logged into the system and locked down the test user account -- which is also how they got caught because they then had to log in with their actual ID and The Powers That Be could pinpoint who exactly was doing it.
So, yeah, lock down invalid user account IDs.
And there's something deeply sad about "they prioritized the better jobs, so we blacklisted them".
Which probably means Instagram admin intervention.