Reputation: 21486
I'm teaching classes on the new Java constructs. I've already introduced my students to Optional<T>
. Imagining that there is a Point.getQuadrant()
which returns an Optional<Quadrant>
(because some points lie in no quadrant at all), we can add the quadrant to a Set<Quadrant>
if the point lies in a positive X quadrant, like this:
Set<Quadrant> quadrants = ...;
Optional<Point> point = ...;
point
.filter(p -> p.getX() > 0)
.flatMap(Point::getQuadrant)
.ifPresent(quadrants::add);
(That's off the top of my head; let me know if I made a mistake.)
My next step was to tell my students, "Wouldn't it be neat if you could do the same internal filtering and decisions using functions, but with multiple objects? Well that's what streams are for!" It seemed the perfect segue. I was almost ready to write out the same form but with a list of points, using streams:
Set<Point> points = ...;
Set<Quadrant> quadrants = points.stream()
.filter(p -> p.getX() > 0)
.flatMap(Point::getQuadrant)
.collect(Collectors.toSet());
But wait! Will Stream.flatMap(Point::getQuadrant)
correctly unravel the Optional<Quadrant>
? It appears not...
I had already read Using Java 8's Optional with Stream::flatMap , but I had thought that what was discussed there was some esoteric side case with no real-life relevance. But now that I'm playing it out, I see that this is directly relevant to most anything we do.
Put simply, if Java now expects us to use Optional<T>
as the new optional-return idiom; and if Java now encourages us to use streams for processing our objects, wouldn't we expect to encounter mapping to an optional value all over the place? Do we really have to jump through series of .filter(Optional::isPresent).map(Optional::get)
hoops as a workaround until Java 9 gets here years from now?
I'm hoping I just misinterpreted the other question, that I'm just misunderstanding something simple, and that someone can set me straight. Surely Java 8 doesn't have this big of a blind spot, does it?
Upvotes: 0
Views: 148
Reputation: 298539
I’m not sure where your question is aiming at. The answer of the linked question already states that this is a flaw of Java 8 that is addressed in Java 9. So there’s no sense in asking whether this really is a flaw in Java 8.
Besides that, the answer also mentions .flatMap(o -> o.isPresent()? Stream.of(o.get()): Stream.empty())
for converting the optional, rather than your .filter(Optional::isPresent) .map(Optional::get)
. Nevertheless, you can do it even simpler:
Instead of
.flatMap(Point::getQuadrant)
you can write
.flatMap(p -> p.getQuadrant().map(Stream::of).orElse(null))
as an alternative to Java 9’s
.flatMap(p -> p.getQuadrant().stream())
Note that
.map(Point::getQuadrant).flatMap(Optional::stream)
isn’t so much better compared to the alternatives, unless you have an irrational affinity to method references.
Upvotes: 1