3 ms·
I disagree with some of your points. The fact that you can get a null instance of Optional is not Java specific - Scala has the same issue, for example. Saying
by nrinaudo 11y ago
I disagree with some of your points.
The fact that you can get a null instance of Optional is not Java specific - Scala has the same issue, for example. Saying that Optional does not sort any problem because there is no way to enforce it cannot be null is just wrong - it sorts plenty of problems, just not all of them (you didn't mention the case of an optional that contains null, which is unpleasant as well).
You can indeed call .get - so can you in Scala (.get) or Haskell (fromJust) with exactly the same semantics. What do you propose for the case where you know that there is a value in there but can't make the type system aware of that fact (you've called isPresent beforehand)? pattern matching and fail in the empty case? How is that different from calling get? Is it because of the fact that the exception is unchecked? In that case, why not throw a more specific, checked exception through orElseGet? And if you know that there is data to be had, isn't that exactly why we have unchecked exceptions in the first place?
You absolutely are required to handle the not-present case - you can't treat an Optional<T> an a T, and someone will need to decide what to do at some point. Either the caller (ie you return an Optional yourself after mapping into it) or you. There's a wide range of ways you can do that, one of which being "I want to fail if there is no data" - that's either .get if you don't need a checked exception or .orElseGet if you need something more constrained. You can also decide to use a default value, or o different code path entirely...
Optional has issues - it can contain reference to a mutable variable, for exemple, or you might find yourself with a null optional or an optional that contains null. It's not perfect. It's also a lot better than the alternative, null, as it lets you communicate some of your constraints to the compiler and allow it to catch certain kinds of errors at compile-time rather than at runtime. Rather like the rest of the Java type system, in fact - it's far from perfect, it doesn't catch all type errors at compile time, but it's (arguably) better than a fully dynamic one.