• 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 Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • paul wheaton
  • Jeanne Boyarsky
  • Ron McLeod
Sheriffs:
  • Paul Clapham
  • Liutauras Vilda
  • Devaka Cooray
Saloon Keepers:
  • Tim Holloway
  • Roland Mueller
Bartenders:

Traversing a stream of Characters

 
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Suppose I have:

Does it mean that StreamImpl{} will enclose the five operations and each of the non-terminal operations will in turn implement its own spliterator?  As in the following?
The source_spliterator will be passed to the filter() method
The filter_spliterator will be passed to the map() method
The map_spliterator will be passed to the limit() method
The limit_spliterator will be passed to the max() method

Suppose also that in the previous case where I have list,stream().map().forEach(), I do the following:

To set the ball rolling, I would need to do something like:

What will repeatedly invoke x_Spliterator.tryAdvance() so that all the elements in x_spliterator can be processed?
 
Bartender
Posts: 15737
368
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Biniman Idugboe wrote:Does it mean that StreamImpl{} will enclose the five operations and each of the non-terminal operations will in turn implement its own spliterator?  As in the following?


Almost.

The source_spliterator will be passed to the constructor of the stream on which the filter() method is called; the filter() method has access to the field that holds the spliterator.
The filter_spliterator will be passed to the constructor of the stream on which the map() method is called, the map() method has access to the field that holds the spliterator.
The map_spliterator will be passed to the constructor of the stream on which the limit() method is called, the limit() method has access to the field that holds the spliterator.
The limit_spliterator will be used by the max() method to create a result, because it's a terminal operation.

To set the ball rolling, I would need to do something like:


No. StreamImpl has no previousOperation field.

anotherStream.spliterator holds the spliterator that your call to map() created, and anotherStream.spliterator.previousOperation holds the spliterator that you created with your call to new MappingSpliterator(spliterator). anotherStream.spliterator.previousOperation.previousOperation holds the spliterator that you passed to the constructor of MappingSpliterator. I think you confused yourself by constructing the MappingSpliterator yourself, rather than letting a call to map() do it. Then you created a second MappingSpliterator by calling map().

Also, this doesn't set the ball rolling, because you didn't call a terminal operation.

What will repeatedly invoke x_Spliterator.tryAdvance() so that all the elements in x_spliterator can be processed?


A terminal operation, like forEach() or reduce() or max().
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Permission to divert this discussion a little bit.  I have been of the understanding that when an interface is implemented, all the abstract methods in the interface will be given codes in the process of implementation.

The Stream interface has several abstract methods.  No codes were added to the methods.  Does implementing an interface simply mean incorporating the interface into a class definition?
 
Stephan van Hulst
Bartender
Posts: 15737
368
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
No, you have to implement all of them, if the class is not abstract. I only showed the map() method because otherwise the class definition would become much too long and complicated to be of any use for this discussion. I indicated that by included ellipses (...) in the class body, which is normally not allowed.
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Good to know that I did not deviate far from the discussion.

The above line of code is kind of confusing to me because the variable named spliterator was not assigned any object up till this point.  Neither was the previousOperation assigned any object.  Is it the case that a null is accepted as a spliterator?
 
Stephan van Hulst
Bartender
Posts: 15737
368
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The spliterator variable is a final field of StreamImpl and its value is assigned in the constructor.

The previousOperation variable is a final field of MappingSpliterator and its value is assigned in the constructor.

At no point are the values of these fields null.
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Still not clear to me.  In what order does the new StreamImpl<>(new MappingSpliterator(spliterator)); execute?
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What I mean is, suppose I break the code down like the following:

Where was the variable named spliterator assigned an instance of Spliterator<T> ?
 
Stephan van Hulst
Bartender
Posts: 15737
368
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
When the StreamImpl instance was created that wraps spliterator. This is NOT the same StreamImpl as the one that wraps the new MappingSpliterator, but a StreamImpl that represents the operation that is performed before map().

Let's take the example you wrote before:

Another way of writing this is:

As you can see, each stream is constructed by passing it the spliterator that implements the operation that is to be performed on all the elements of the stream. Each spliterator is constructed by passing it the spliterator that was contained in the previous stream.

Note that Stream really only serves as a container for a spliterator. A shorter way to write the above would be:

This code is hard to read though, and that's why the Stream interface exists: to decorate a Spliterator with operations like filter(), map() and limit(), so we can write the following instead:
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
If I understood what you just said, the stream() method implements the Stream interface behind the scene and each abstract method is given codes that implement the method's own version of Spliterator<T>.  The resulting spliterator actually performs the operation expected of the method.  That certainly saves the programmer a lot of headache.  Right?
 
Stephan van Hulst
Bartender
Posts: 15737
368
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I think you've got it.
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I cannot thank you enough for tolerating me.
reply
    Bookmark Topic Watch Topic
  • New Topic