Introduction to Streams- Functional Programming in JAVA 8- Part 9

Basically Streams are a powerful new way of working with collections in JAVA 8.
In this post we will be only discussing working of lambdas with Streams. Let’s take a look into the proper definition of Streams as per javadoc.
“A sequence of elements supporting sequential & parallel aggregate operations.”

Don’t be so confused with the definition, I will help you in understanding it.

Suppose you have 6 cars & you have to have work done on these cars.

1 2 3 4 5 6

Suppose you want to have below 3 works to be done on each of these cars.

  • paint the chassis
  • fix engine
  • fix tyres

And you have 3 people who can work on each of the above works. So, one person can paint the chassis, another can fix the engine and the other one can fix the tyres. So 1 work for 1 person and we have 6 different cars.

One way is, each of the person can go across the 6 cars one by one and do his job.

1 2 3 4 5 6

paint chassis—————————————————————————————————–>

1 2 3 4 5 6

fix engine——————————————————————————————————–>

1 2 3 4 5 6

fix tyres———————————————————————————————————>

So, what is happening here is, all the 3 persons who need to work on the above 6 cars are iterating over the cars every time. There are 3 iterations that are happening.
Looping over the cars everytime is just an overhead. This is something not a standard practice.
Standard way of fixing a collections of cars in car manufacturing is by using a mechanism called assembly line.

Have the people stay at a particular location, then you have an assembly line(like conveyor belt) & it has cars on them & then these cars move in order & then these people stay where they are & the cars come to them. They each(persons) know what to do as cars passed through them.
Basically you have looping(iterating) isolated out in a separate thing which is the conveyor belt(assembly line) & then all these people who need to work on these individual element they just stay where they are, they don’t have to worry about the looping part.
Streams lets you build the assembly line & then you have to declare the action that you need to do for each element.
Streams is a conveyor belt where each element in the collection goes through list of actions that needs to be done & each element has the right kind of action applied to it.
Let’s take a look at below example, where we want to have a sublist of people that have firstName begins with “C”, and get that list as a separate instance and print the values. One way is to looping through the list of people and filtering out the person records that we are interested in and then looping through it again and printing it again. But not very efficient:-

public class StreamsExample1 {

	public static void main(String[] args) {
		List<Person> people=Arrays.asList(
				new Person("Charles","Dickens",60),
				new Person("Lewis","Carroll",42),
				new Person("Thomas","Carlyle",51),
				new Person("Charlotte","Bronte",45),
				new Person("Matthew","Arnold",39));
        }
}

What we can do is, create an assembly line of the above people objects, and set the right operations to do the right thing and run the assembly line. The way to do this is by using a Stream method. As of JAVA 8 every collection comes with a stream method.

people.stream();

Above stream method of people collection returns an object of Stream(think of it as an assembly line), basically putting those Person objects on a conveyor belt.Stream class has a bunch of methods that you can call on it.

people.stream()
.forEach(p->System.out.println(p.getFirstName());

Not too fancy. Putting all above persons on the conveyor belt and for each element that shows up on the conveyor belt we are printing out the firstName.
Let’s add some trick here. We want only those firstNames to be printed that starts with letter “C”.

people.stream()
.filter(p->p.getFirstName().startsWith("C"))
.forEach(p->System.out.println(p.getFirstName());

filter is like a check on conveyor belt, anything not satisfying it is filtered out. Anything that passes filter goes to the next in assembly line i.e. forEach.

public class StreamsExample1 {

	public static void main(String[] args) {
		List<Person> people=Arrays.asList(
				new Person("Charles","Dickens",60),
				new Person("Lewis","Carroll",42),
				new Person("Thomas","Carlyle",51),
				new Person("Charlotte","Bronte",45),
				new Person("Matthew","Arnold",39));

                people.stream()
                .filter(p->p.getFirstName().startsWith("C"))
                .forEach(p->System.out.println(p.getFirstName());
        }
}

Moral is , if you want to do multiple operations on a big collection the avoid big loops, or avoid multiple loops. Use Streams instead, streaming the collection & on the stream you can have multiple operations performed for each element of the Stream & each operation can modify the Stream.