Optional (was: Streams)
Brian Goetz
brian.goetz at oracle.com
Fri Sep 14 08:14:03 PDT 2012
On 9/14/2012 1:23 AM, Sam Pullara wrote:
> 2) Optional should implement more of the Stream API like flatMap and
> some others.
This is a reasonable option. Currently, the Optional class is a
strawman, focusing on the methods needed for dealing with absence and
omitting these convenience methods. Happy to consider this.
> I also hate that with Optional.none() often needs to be witnessed and
> not a big fan of using a constructor for Optional:
This is a problem not with Optional, but with type inference. In Java 7
we do very limited type inference of generic methods in nested method
call contexts. This should improve.
Remi wrote:
> Is there a document somewhere that explain the pro and cons of using Optional ?
The pros are simple: there are eager stream methods that may return
nothing. (Lazy methods like filter can return an empty stream.) The
"obvious" way to deal with this is to return null. But this has
multiple disadvantages:
- If null is a valid value, you're hosed just like when map.get(key)
returns null; you can't tell the difference between "no mapping" and
"mapping with value=null".
- People forget to do the null check, and get NPEs. Explicit optional
doesn't have this risk; the type system saves you from yourself.
- For primitive-valued streams, we can't even coopt null here.
- Optional provides a means of doing the null check in a fluent
manner. Compare:
T result = collection.stream()
.filter(...)
.map(...)
.findFirst();
if (result == null) {
throw new NoSuchFooException();
}
return result;
and
return collection.stream()
.filter(...)
.map(...)
.findFirst()
.getOrThrow(() -> new NoSuchFooException());
Many people like to harp on the performance issues here, but I think
those are red herrings. If you look at the use of Optional in this API,
it shows up in exactly one situation: at the end of a bulk operation
that might yield no results. There is no List<Optional<T>> anywhere,
there is no O(n) Optional-boxing anywhere. It is a small O(1) overhead
which gives a significant improvement in safety and expressiveness.
This tradeoff is totally worth it.
(It may even be that the VM can eliminate the Optional box someday via
box elimination, at which point the performance cost is zero.)
David wrote:
> I don't know - to me Optional<T> is Pair<A, B>'s brother. Both are
> useful, in their way, but both have potential to massively stink up
> code. I don't really believe the benefits are worth it - I mean the
> best improvement we get isn't an objective "it's faster" or "it
> allows more optimal code paths", it's purely a style thing and it
> does have a cost. I don't like it; I think it's going to result in
> things like:
>
> Map<String,Optional<List<Optional<String>>>>
Yes, if you invent fire people will burn themselves. But, I'm with Tim
on this one. In the cases where we've used it, it is just the right
thing, and food tastes better and is safer when cooked.
Doug wrote:
> But it may be worth breaking some consistency for
> the sake of usability in supplying a few such choices
> in Stream API. In particular, findAny
> Optional<T> findAny();
> T findAny(T ifNone);
These are certainly easy enough to implement, and might carry their
weight if "use a default value" were the dominant fallback action. Is
it? Or is throwing just as common / more common? Tim and Sam, what's
your experience here?
More information about the lambda-libs-spec-observers
mailing list