I know there are students in this class and we're going to discuss topics that will help to make your
code clean and concise while working with collections in the race.
They will talk about Stream API at the beginning of the lesson, will give an answer what stream API
is.
I will explain to you why we need to use three API with race and collection sometimes after this class
and you will understand what the conveyor belt is and what terminal and non terminal operations are.
You are going to learn how to create stream and how to process elements with the help of Stream API.
I'm going to show you really a lot of examples today.
I will teach you how to create a stream from array and how to convert at to map with the help of Stream
API.
In this lesson, we are going to have a lot of practice because one of the ways to understand this topic
better is to understand how you can apply this knowledge on practice.
Let's start and to start with, let's create a definition of stream API.
If we would open official documentation from Oracle for Jayaweera to Stream Package will see that this
package contains classes to support functional style operations on streams of elements such as mass
produced transformations, onco actions.
I believe for people who didn't work with streams, this definition doesn't bring a lot of clarity.
So let me explain you the same.
In more simple words, stream application programming interface is a set of interfaces that allow to
process elements and to perform operations with them in containers and arrays with the help of functional
interfaces.
So to perform operation on the group of elements, you can create lambda functions or use Macit references
that in turn significantly simplifies your code.
Does it make sense?
Now let me perform an overview of one important interface from Jowett Ustream package.
This will help you to understand our practice examples.
I would say that one of the most important interfaces is stream interface.
What it is for string interface represents a sequence of elements supporting sequential and parallel
aggregate operations.
This is hard to understand.
Believe me, I know what you feel.
Usually I ask my students to imagine conveyor belt and on this conveyor you have elements from your
collection and as a conveyor belt rolling, you take each element from it and perform any modifications
with it.
Before we dive deeper to code examples, I want you to understand, at least on a high level, the next
example.
Imagine that you have a list of products and you have a task to keep on that products that has more
than one thousand items in the warehouse and decrease price for these products on 10 percent.
This business logic should change the price for products, and this in turn should motivate customers
of the online store to buy these products while price is reduced.
How would you do that?
You would create the container of products.
Let's imagine that this is a box that is full of products and put all products on conveyor belt.
After that, you will check what products has more than one thousand items in warehouse.
You will remove from Canberra products that you are not interested in.
That means you have to apply a function that knows how to filter elements.
After that, you will modify price for each product.
That means you have to apply functions that modify state of the product and only after that the end
of the conveyor belt, you would gather all elements together back to the box.
Is it clear now you can understand that the functions that was applied for each element on the conveyor
belt, they are called non terminal also.
They might be called intermediate functions or it would be opportunism, conveyor operations and the
mass that terminate conveyor are called terminal operations.
We also can say that each non terminal operation at Listener to the Stream listener modifies the element
and pass it to another listener.
This is called stream processing terminal and non terminal operations.
Create Stream Pipeline.
Stream Pipeline consists of the source that is our collection of elements or array followed by intermediate
operations and ended with terminal operation.
Let's consider another case.
You may have multiple lists of products.
How it can be.
You have different warehouses and each warehouse contains information about the products there.
So you have multiple lists of products from each warehouse.
This may happen when Demand-Driven design of your application declares that you have type warehouse
that in turn can return list of products.
And imagine that you have a list, our houses in our example, you have a lot of their houses with products
we can create, can aware of their houses, but we can also have the functions that would tell how to
extract products from these warehouses to have conveyor of products.
And after that, we are going to have similar to previous example, logic will filter elements and will
perform price modification, I believe.
Now you understand what we are going to learn today.
We're going to learn terminal and not terminal functions to perform operations with elements in streams.
Now, let's look at the good examples that I prepared for this lesson.
To understand how streams work will start from reproducing the case that you saw on slides.
All classes are stored in one file to keep all examples related to this lesson grouped and to not switch
between the different types during the lesson.
Here we have a class in its price name and the amount of items in their house.
Also, you can see a special constructor getters and setters to string Masset for the bag and purposes.
And here you can see a warehouse type for the sake of our next examples.
This class has only one field list of products.
Also, there are two masses, getter and setter, to retrieve and to set products accordingly.
Now imagine that I have a list of products.
You can see that I created multiple different products here and put all of them into the list to create
stream.
From this list, I have to just go through Method Stream is the default method in collection interface.
So all collections have be method.
After we create a stream we can call intermediate operations and at least inners.
For example, let's reproduce a situation from the slides that we saw at the beginning of our lesson
I call filter method.
Let me open the source code of Feltham.
As you can see, that filter method takes predicate all intermediate functions, return the stream objects
that allows us to create a chain of MassArt in locations.
Filter message returns a stream consisting of the elements of the stream that match the given predicate.
That means in case predicates returns true for some element, we should keep this element in the stream.
Let's get back to the demo file.
We use simple predicate here.
We want to keep on our conveyor belt only products that have more than 1000 items in the warehouse.
After that, I want to apply function to each element.
I use math method for this.
Let me open the source code of math, Macit.
This message returns a stream consisting of the results of a the given function to the aliments in the
stream.
In our particular case, we modify product and we return the same product to the stream we set.
The new price set is ten percent less than the original.
One important thing to know here is that intermediate operations are lazy.
This means that they will be invoked only if it is necessary for the terminal operation execution.
Let's give you the understanding that this lambda functions will be executed only in case a terminal
operation and the end of the chain.
And now when I did everything I wanted, I want to create a collection of items that are currently on
the conveyor belt I call terminal function collect.
Let's review the source code of collect Macit here.
We can see that this massive tax collector as an argument.
But what is a collector?
We have only one way to learn this from the source code.
We can understand that collector is a specific type that accumulates input elements into mutable result
content.
But where to get the implementation of collector?
Usually engineers use collectors glass to get any collector that is needed.
Let me show you the source code of collectors glass this glass also from Jemmett Ustream package.
And in the Masset outline you can see that we can get different collectors.
The most popular, in my opinion, are the ones that are returned by the next masses to least to set
the map.
Also, you can get collectors that will collect all your elements to modify modifiable least.
For example, most of the masses are describing here.
That's why I don't see the sense into naming all of this matter.
Just open the source code of this class to investigate what other collectors you can use.
By the way, at the end of the lesson, I will leave a cheat sheet for you where I will gather all the
most popular masses, including the terminal functions.
Let's get back to our demo file.
In this case, I want to group all elements from my stream into the container.
I call collect method and pass collect the.
Is it a might the least Masset implication, is this example clear so you can see massive change here
with multiple intermediate functions and then I have one terminal operation.
Where did they get these intermediate masses?
You can open string type to investigate.
The rest of the masses here will review these in a minute.
Let me finish the example we already started.
Let me get back to the demo file.
And after I created the list, I want to print all elements to console from the new line.
But instead of creating foreach loop, I will use the feature of Stream API.
I create a stream using the variable of modified products.
After that, I call for each method that takes consumer as an argument and I pass mast reference here
out property of a system class.
His method printer lan that we use very often during the bargain of our programs.
So I just use reference to this massive let me run the program to prove you that it works.
And here we go.
You can see that I have only three products with modified price.
Awesome.
Everything works as expected.
Now let me reproduce the second example from our presentation.
Imagine that we have multiple warehouses.
I create a few warehouses, objects here.
Each warehouse has lists of products.
That's why I add a different list of objects to the warehouses here.
And imagine we have to iterate over all products to decrease price only for products that have more
than 1000 items.
First of all, I group all my warehouse objects into one list.
Now I create a stream out of this list.
After that I call flat my math.
What is it for?
This method exists to extract elements from NASA once this method will return stream consistent of the
result of replacing each element of the stream with the contents of a mapped stream produced by applying
the provided map and function to each element.
Is it clear will path function to this method that will produce stream of elements from each element?
In our particular case, we have to get products from each warehouse object and create a stream on list
of products.
Before we call this flat map method, we have conveyor belt of warehouse elements and after we called
flat map, we have stream of product elements.
Can you understand now how we can transform data in our stream?
After that, we are filtering and applying function to all elements.
Now let me show you one more thing.
Imagine that according to some massive contracts requirements, you have to reach an array we can call
to array Massud instead of collect.
But in case we would just call Thouret Array method, we would get array of objects.
What to do in this case, I have to pass the Massud that will create array of the specific types that
I need.
What method can create an array of product constructor?
That's why I specify type here array of product and positive reference to a constructor according to
syntax requirements.
I have to write the new keyword here.
Can you understand now what this meant?
Now Java can create object of product array.
After that I want to print all elements to console from new line.
But we have an array this time can create stream from array.
Yes I can.
I have to call stream Massud from arrays class and parse array of products there.
That's how easily you can create three from any array.
Also during the discussion of functional interfaces, I promise to show you one method and how it might
be helpful.
While working with Stream API, I'm talking about identity Masset from function type.
Imagine that you want to convert list of products to the map type where you're going to have product
name as a key and product type as a value that is mapped to this key.
How to do that.
You'll remember at the beginning of the lesson I created products placed in this example.
I use the same list of products, I create stream code, collect method.
And after that I called to map Masset from collectors' class and past two functions.
The first one should create keys, and the second one is a function that can create product values that
are associated with a specific case.
Taking into account, I don't need to modify a product, I should return the same product.
That's why I use identity MASSATA function type here.
Identity MassArt returns the same object, does it make sense, the last good example that I want to
share with you is map to end and some that I would even say that a group of mass that you will use and
these two are just one of many.
There are numerous of business cases when they need to process collection of elements and find is a
max price or some old values of some field or something similar.
To perform these operations, we have to convert our regular stream to in stream or double stream along
stream.
That's why Stream Type has such masses as map to end, map to double mapped along this massive stage
function as an argument then can extract some no value out of current item in stream and these masses
rich on specific stream type like any stream that will stream along stream.
These types declare new methods.
For example, imagine the case when you need to calculate total amount of items of all products in the
warehouse aggregate stream.
And after that cool map to Inmarsat and parse function that returns into value based on each product,
is that clear?
And after that I can call some method.
This mass at will sum all integers in my end stream that I received after map to Inmarsat invocation.
And here I bring the total items amount to consult, by the way, instead of some you can call Max mean
average or any other methods you would like.
Myside examples from this file, I also prepared a lot of other examples for you, which are the masses,
I believe, linked to this file in attachment to this lesson.
I want you to investigate these good examples by yourself after the lesson, because technical is a
syntax is the same.
And you saw already a few examples.
Some of the methods are used very rare.
Some of them are used more often.
We'll talk about the masses in a minute.
But remember that you can find any good example with any message from Stream API by searching through
this file.
Now, when you saw how you can use the masses and stream API, it is only a matter of what that you
want to call.
We cover all aspects of using stream API from the syntax standpoint.
Now we have to learn the masses that you might want to use while working with streams.
I want to show you a cheat sheet, I call it.
So was the main operations with streams and shared examples.
Remember, you can use a cheat sheet in case you forgot something on this slide.
You can see how you can create a stream with examples.
Some of them we already reviewed.
I'm talking about creating a stream from collections and from array.
Let's review other options.
We can create stream of elements if we want.
We can create stream of lines in case we read file.
We will learn more about this during the topic.
Input output streams in Java.
Also, as you can see here, we can create a stream from stream.
We can use Stream Builder to add elements.
And after that stream also you can invoke parallel stream that would process all elements in different
threats of execution.
Ensured parallel stream will not always bring you better performance because coordination of multiple
threats of execution also requires some calculations.
That's why use parallel stream only with the amount of data.
It is hard to see what should be considered as Beke because it will depend on the operations you are
going to perform and stream.
It will also depends on the type of the object that you are going to use and how big it is.
I would even say that in case you are not sure whether the parallel stream in some particular case always
opt for regular stream in such cases.
Also, we can create infinite sequential order stream produced by iterative application of a function
to an initial element.
Besides that, we can create an infinite sequential stream where each element is generated by the provided
supply.
In other words, we can pass a function that can generate elements and create a stream.
To be honest, I didn't use the last two options very often.
So now you know all possible ways to create stream.
Let's move on.
On this slide, you can see different intermediate methods.
Some of them looks familiar to you because we had examples with those masses.
You already know when you might want to use filter, map, map to end flatman methods, don't you?
You also can use skip method to skip specific number of elements you can call distant Masad to get stream
without duplication in case you want to apply consumer function to each element you can call peak MassArt.
Usually it is used for debugging purposes, the print element to console to investigate the state of
a stream lamet.
Masset allows you to limit the number of elements in your stream source.
It allows us to source elements in stream by natural ordering.
There is also overloaded version of this method that takes Comparator as an argument to define the source
and order.
Using these intermediate operations, you can do amazing things with data manipulation.
Let's look at the next slide and on this slide you can find a list of terminal operations.
Today during the demo, you saw collect Masset for each entero find first method returns, the first
element from stream.
This might be useful in case your source elements in stream and want to take the first elements after
sorting, find any MACIT returns, any element from stream patterns that these two methods return object
of type optional.
This is not the lesson about optional, but ensured optional is a type that is used as a container for
objects that may or may not contain and nonono value.
Also, these types introduce API to extract value from container or perform as operations in case a
container is empty.
We can call Count Massud in case we want to get a number of elements in this stream and any match non-match
and all march methods take predicate to return.
True or false?
I believe that it is clear from the method names that any match will return true in case at least one.
The elements from streamy, the conditions of predicates that we passed to this massive non-match will
return true in case non of elements Margitza Predicate and all March will return true only in case all
elements march pre-cut main and maximizers.
I believe these are self describing this massive state comparator as an argument for each order.
It must is similar to for each Massett, but it also supports order of elements in the stream.
Reduce mass performs reduction stream operations that allows us to produce one single result from a
sequence of elements in this operation usually take part three participants.
They are a regional element.
It is also called identity.
The second participant is an accumulator.
This is a function that takes two parameters, a partial result of the reduction operation and the next
element of the string.
And the third participant is a combiner.
This is a function that is used to combine the partial result of the reduction operation once the reduction
is paralyzed or when there is a mismatch between the types of the accumulator arguments and the types
of the accumulator implementation.
And I know that this can sound not clear, but don't worry about that after this lesson.
Take your time to investigate the examples.
I didn't show you this example because to be honest, this function is not used super often, really.
So take your time to investigate examples and feel free to ask questions in case you have any.
That's all what I wanted to share with you today.
Now let's recap what we have learned today so that we learned really a lot of things.
But let's try to sum it up.
We understand what Stream API is now.
We know how to create stream, how to use intermediate operations and how to use terminal operations
on real life examples.
You saw how you can apply your knowledge about Stream API.
Also, you got a lot of examples that you can use during the development when you need.
And now let me show your homework.
You can find multiple tasks here.
The important thing in each task is to implement those with the help of Stream API and functional interfaces.
You can practice a lot in writing your own lambda expressions and then processing elements in stream
read tasks attentively.
I edit as much details as I could in each task and remember, in case you have any question gunshy to
ask me that.
So what I have for you for today, thanks a lot for your attention.
Have a great day and see you in the next lesson.