Win a copy of Testing JavaScript Applications this week in the HTML Pages with CSS and JavaScript forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Bear Bibeault
  • Ron McLeod
  • Jeanne Boyarsky
  • Paul Clapham
Sheriffs:
  • Tim Cooke
  • Liutauras Vilda
  • Junilu Lacar
Saloon Keepers:
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • fred rosenberger
  • salvin francis
Bartenders:
  • Piet Souris
  • Frits Walraven
  • Carey Brown

Java 8 Stream, Optional don't understand this particular case

 
Greenhorn
Posts: 13
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello,
I'm really having tough day grasping of following code example.  I understand this code:


But don't understand this code:



In the first code , returns Optional<Car>, and then we are able to .
But in the second code, from    we get  Optional<Car> , but in this case we aren't able to write .
I don't understand the flow/Stream pipeline of the second code. I will be really grateful if You could help me.
Classes:

 
Sheriff
Posts: 7108
184
Eclipse IDE Postgres Database VI Editor Chrome Java Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm not an expert in Streams, but I think that in the second method, .map(Person::getCar) returns a List<Optional<Car>>, not just Optional<Car>.
 
Sheriff
Posts: 21972
106
Eclipse IDE Spring VI Editor Chrome Java Ubuntu Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
For Optional, flatMap flattens an Optional<Optional<T>> into an Optional<T>.
For Stream, flatMap flattens a Stream<Stream<T>> into a Stream<T>. That means you can't use Optional.flatMap directly on the stream as in your first code snippet.

What your second code snippet does is map (on line 4) each Optional<Car> to Optional<Insurance> as in your first code snippet, then map (on line 5) each of those to Optional<String> as in your first code snippet. The extra flatMap(Optional::stream) converts the Stream<Optional<String> into a Stream<String>.

If you want to keep your code a bit more readable, you can use Optional.stream in between already:

I've put two stream operations on the same line, which I usually don't do, to make it clear that we want to treat them as one.
 
Rob Spoor
Sheriff
Posts: 21972
106
Eclipse IDE Spring VI Editor Chrome Java Ubuntu Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Knute Snortum wrote:I'm not an expert in Streams, but I think that in the second method, .map(Person::getCar) returns a List<Optional<Car>>, not just Optional<Car>.


Almost, it's Stream<Optional<Car>>.
 
Marshal
Posts: 69847
278
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Please avoid long // comments, which make the lines too long to read readily on screen. Use multiline /* comments */ instead.
Please aso aways say where such quotes come from.

Jonas Ramanauskas wrote:. . .
. . .

The comment on line 3 is incorrect.
  • 1: It doesn't convert the List to a Stream, but passes the information from the preceding Stream<Person> to a different Stream.
  • 2: I cannot ell what sort of Stream it produces. It will only produce a Stream<Optional<Car>> if the return type of getCar() is Optional<Car>.
  • If the name optCar means that Stream is indeed handling Optionals<Car>, then you want to look in the Optional documentation, where you find what the flatMap() method does. It isn't an analogue of Stream#flatMap(). This is just an exercise, but it will keep running even if the insurance is null.

    Now, having a null insurance policy is nothing unusual. I am sure there are people within one mile of here who, if asked by the police for their policy, would return null, but it isn't how I would design a class.

    Using flatMap() at that stage allows you to hae a Stream<Optional<Insurance>>. Otherwise you would return an Optional<Optionals<Insurance>>. Anybody want a Stream<Optional<Optional<Insurance>>>? You are flattening the output to create a new Stream<Optional<Insurance>>.
    Then you use the map() method which is going to give you an Optional, which needs to be indlucded in a Stream<Optional<String>> using the orElse() call to deal with the situation where there is no value (=empty Optional).

    At least I think that is what is happening. I have not noticed this behaviour before. I have however noticed that my Urma Fusco and Mycroft has a very similar example to what you showed, in chapter 11 (page 275), which I think will explain it better than I can.
     
    Jonas Ramanauskas
    Greenhorn
    Posts: 13
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Rob Spoor wrote:For Optional, flatMap flattens an Optional<Optional<T>> into an Optional<T>.
    For Stream, flatMap flattens a Stream<Stream<T>> into a Stream<T>. That means you can't use Optional.flatMap directly on the stream as in your first code snippet.

    What your second code snippet does is map (on line 4) each Optional<Car> to Optional<Insurance> as in your first code snippet, then map (on line 5) each of those to Optional<String> as in your first code snippet. The extra flatMap(Optional::stream) converts the Stream<Optional<String> into a Stream<String>.
    .....



    Thank You,very very much!. O my god at last. I studied your post , and it became clear to me. This your line "That means you can't use Optional.flatMap directly on the stream " gave sudden  spark to my brain.

     
    Ranch Hand
    Posts: 143
    5
    IntelliJ IDE Eclipse IDE Java
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Knute Snortum wrote:I'm not an expert in Streams, but I think that in the second method, .map(Person::getCar) returns a List<Optional<Car>>, not just Optional<Car>.



    map() always returns a stream as seen from its method signature below. In the OP example, it returns Stream<Optional<Car>>. We can collect the map elements into a desired collection such as list by using collect() method.


     
    Rob Spoor
    Sheriff
    Posts: 21972
    106
    Eclipse IDE Spring VI Editor Chrome Java Ubuntu Windows
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Jonas Ramanauskas wrote:


    Correct, apart from (Optional::stream) not doing anything by itself. .map(Optional::stream) returns Stream<Stream<String>>. And whenever you have a Stream.map operation that returns Stream<Stream<T>> for whatever T, using flatMap instead will get rid of the inner Stream part (similar for Optional).
     
    Jonas Ramanauskas
    Greenhorn
    Posts: 13
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Rob Spoor wrote:

    Jonas Ramanauskas wrote:


    Correct, apart from (Optional::stream) not doing anything by itself. .map(Optional::stream) returns Stream<Stream<String>>. And whenever you have a Stream.map operation that returns Stream<Stream<T>> for whatever T, using flatMap instead will get rid of the inner Stream part (similar for Optional).



    Thank You!
     
    Rob Spoor
    Sheriff
    Posts: 21972
    106
    Eclipse IDE Spring VI Editor Chrome Java Ubuntu Windows
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    You're welcome.
     
    Honk if you love justice! And honk twice for tiny ads!
    Building a Better World in your Backyard by Paul Wheaton and Shawn Klassen-Koop
    https://coderanch.com/wiki/718759/books/Building-World-Backyard-Paul-Wheaton
      Bookmark Topic Watch Topic
    • New Topic