I know the excuse that they are just meant to be used to wrap the return value of a function that might be null, rather than as a guard against NPEs, but that just means we’ve got a crappy, verbose Optional class ... and NPEs.
It was the most half assed attempt to fix the billion dollar mistake [0] anyone could have come up with. It needed syntax and compiler support, not a stupid wrapper class.
I don’t really get your other arguments. I think the problem has been solved better in other languages including Swift, Kotlin and Rust, and Java could have learned from them, but didn’t. I can’t see why direct language support couldn’t have been added to solve this “billion dollar problem”. Even the Elvis operator would have helped.
I'm absolutely convinced that's true for some of them. I was never 100% convinced it was true for all of them.
Java also had the unfortunate destiny of becoming popular at the time where "OOP all the thing" was a mantra in tech circles. Also design pattern were all the rage.
Those things have a huge inertia, and while Java is not a much more flexible language, the image stuck, to the point that new comers still implement singletons in the wild.
Java was a product of “OOP all the things”, it wouldn’t have existed without it.
It was very much a marketed language and a language designed to be sold to top heavy corporations. This fueled a lot of the crappy design decisions, the hype and the culture.
“OOP all the things” predated (and led to) Java, it wasn’t a product of Java (C++, Objective-C, Object Pascal and, well, a bunch of other things from the late 1980s and early 1990s were where it got started.) Java was about a decade into it.
I know not everyone will agree with me, and that’s fine, but I always found Java to be far more pragmatic than, for example, C++, which well and truely predated Java.
Stuff like "everything is a class".