The only value Optional has over regular values is that the developer has to assume the value can be missing - but the same was true for nullable properties.
The only value Optional has over regular values is that the developer has to assume the value can be missing - but the same was true for nullable properties.
That hasn't been a problem for me in practice. It's pretty clear that a reference to Optional should never be null. It can be statically or dynamically checked with @Nonnull or a precondition.
> but the same was true for nullable properties.
It's inconvenient to have to treat everything as possibly null. It's a lot nicer to create the convention, within one's codebase, that references are always nonnull and only Optional are nullable.
It has for me. Functions have multiple return points, some of them returning "null". Lead developer insists we use Optional<> to clarify that these functions can return null. People go over the function, replacing each instance of "return null" with "return Optional.empty()", but forget some instances. Now we have Optionals that are sometimes null.
Optional allows the code to say "I never intend to return null, only an Optional that may be nothing". In theory, a library/module/whatever that's been converted to use Optional should not have any calls that do return null.
In theory, its no different than a C API that can return a size or -1 for failure. Sure, it could return -2 because the language allows it, but you shouldn't need to check for that in your code that uses it.
By applying these techniques you can quickly create a "demilitarized zone" for null, allowing you to use Optional confidently on the other side. Errors are caught quickly and locally by analysis and assertions. In a large codebase it's not an all at once upgrade, unless you refactor checked by static analysis, but you can be confident in the parts you've upgraded.
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.
That's not possible in Java. `Optional.ofNullable(null)` returns `Optional.empty()`, and `Optional.of(null)` throws a NullPointerException.
A programmer looking at the code for the first time will know, just by looking at the return type, "Hey, this method may not return a record! I'll have to handle that scenario."
Making this clear to users of an API is something that nullable properties can not do. The user has to deliberately ignore the fact that the value might be missing by calling `.get()`.
This looks like a advantage to me, so to say that Option does not solve ANYTHING seems incorrect. It certainly does not solve EVERYTHING.
Well, that's basically the same thing with any nullable return then. Wether I return T or Optional<T>, there might be no record.
Even worse, when I return T, you only have 2 cases : I return something, or I return null.
With optional, you have 3 cases to check : I returned Something, I returned Optional.of(null), or I returned null.
I guess you are either saying (A) to treat every return type as possibly null or (B) to use your judgment when doing null checks of return types.
In case of (A): Do you want to write null-checks for methods like String.toUpperCase() or for user.getLastName()? That would lead to a lot of bloated, dead code. Also do you want to write error handling for all these cases you know can never happen?
In case of (B): NullPointerExceptions are most likely when the user of an API did not expect he might get a null value. For instance user.getDepartment -> null. "What? An employee does not have to have a department?!" In this case you force users of an API to guess if they might reive a null return value. And they might guess wrong, which either leads to dead code or NPEs. Using Optional as a return type makes the difference explicit.
To me, this is much clearer than having to guess on every call and I would prefer this use of Optional or not in an API to an API without Optional and having to check everything.
Optional is planned to become a value type.
Sure, this doesn't live up to the actual guarantees provided by other languages, but that's not the same as being useless.