Hi guys! Have you ever heard of Java Streams? Actually it was introduced in Java 8. Streams are used to process a collection of objects. So, we need some knowledge on Java Collections also, to work with Streams. When we need to do many intermediate operations and get a result based on a collection, streams can be used. It does not change the original data structure. And streams are not data structures also. Rather than storing data into variables and processing in several steps, we can do same thing using streams in one line!! Let's see how to deal with streams now!

NOTE:
We should be familiar with Lambda expressions to get the real benefit of streams.

Basically there are two types of stream operations. They are terminal operations and non-terminal(intermediate) operations.

1. Non Terminal Operations

  • map - Apply some function an create a different output from the stream
  • filter - Select elements that are validated by a predicate
  • sorted - Sort the elements in the stream

2. Terminal Operations

  • collect - Return the result as a list after stream operations
  • forEach - Iterate over the elements of the stream
  • reduce - Reduce the elements of the stream to a single value

We will look into all those operations with example codes next.. There is a huge set of operations available with streams! I will not be able to cover all those. I will cover all the basic ones and essentials.

Java provides a method called stream( ) to convert a collection into a stream of objects:

format   =>   collection_reference.stream()

Otherwise we can use the Stream interface directly to create a stream on the go!

format   =>   Stream.of(1,2,3,4,5)

Basic Operations with examples :



Explanation of the examples related to operations:


Collect Operation

In this example code, I have used collect method in many places. Whenever I want to assign the intermediate resulting stream into a collection, I have used collect operation.


Map Operation

I have used this operation to covert the elements in the stream into another set of objects like squared numbers. Only thing we need to understand the way to define it.


Sorted Operation

I used sorted function to sort the integers and names. By default it uses the basic integer and string comparison. But we can change the implementation in this method. In the code, as as example I have defined sortedNamesDesc list as a result of names list in descending order.


Filter Operation

This is a very useful function that can be used to select elements what we want. Filter method takes a Predicate as a parameter. What is it? Predicate is a Functional Interface in Java. (I think you have basic understanding on Lambda Expressions!) Simply it has only one method which returns a boolean value. So, we can pass a lambda expression which returns a boolean value, as the parameter for filter method. I have defined predicateToGetOddNumbers variable as a Predicate to return true if the element is odd.


ForEach Operation

This method is also useful to loop over a collection. Simply it takes a Consumer as the argument. It can be separately implemented and provided into the forEach loop. Otherwise we can implement the logic as lambda expression, within the forEach loop.

Consumers

So, let's see how to create a Consumer!

There are 2 main types of consumers. They are Consumer and BiConsumer. Look at the below example.

Consumer<String> changeCase = a -> System.out.println(a.toUpperCase());

This converts the string elements in a list, to UPPERCASE. So, we can just pass this consumer as follwing.

names.forEach(changeCase);

Let's consider a Bi Consumer. Actually its use case is related with Map data structure objects.

HashMap<Integer, String> map = new HashMap<>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
BiConsumer<Integer, String> biConsumer = (k, v) -> {
System.out.println(" Modified key = "+ (k+10) + " Value = "+ v.toUpperCase());
};

As previous example, we can pass this also to the relevant data structure. Here, it's a map.

map.forEach(biConsumer);

So, this is about consumers. Instead of consumer, we can also just include the logic in consumer directly to the forEach loop!


Reduce Operation

When we need to convert the elements into one single result, we can use this method on streams. But how? Let me explain. There are some basic concepts needed to understood before using reduce method. Basically it takes two parameters. They are identity and accumulator.

identity :  
The initial value of the reduction and the default result if there are no elements in the stream.

accumulator : 
a function that takes two parameters : a partial result of the reduction operation

Let's take an example. Imagine we need to get the sum of a collection of integers. So, in this case;
what is the initial result? sum = 0 -> identity
what is the function? sum = a + b
So, when this logic is implemented in stream reduce method, it will be like this.

int sum = numbers.stream().reduce(0, (a, b) -> a + b);

To more clarify the accumulator, Java has introduced a simpler way to use some basic logic instead of that kind of lambda expression. According to that conversion is like this.

int sum = numbers.stream().reduce(0, Integer::sum);

(a, b) -> a + b has been replaced by Integer::sum. Every time we can not do this. But Java gives you some basic logic inbuilt, as a support to reduce the code lines.
I think you have understood the concept!! If not, you can ask me on the comment section also...


OK Guys! Now I have fully explained the main operations used in Java 8 Streams. You may have already seen, how streams reduces the lines of code by chaining the operations on the fly. There are inbuilt operations that help a lot to process collections of objects without storing in variables intermediate. We can do various things by chaining these operations. To practice, I will some exercises here for you!

  1. Find sum of only the even numbers in a collection
  2. Display the words in a collection are palindrome or not (ex: abba is  a palindrome, abc is not a palindrome: we get the same word when we read from both the ends)
  3. Find the maximum of the odd numbers in a collection (collection includes both odd and even numbers)
  4. Find the list of names of Person objects whose age greater than 25 (Person has name and age as properties)


Answers for the questions:


So practice guys! You will get to know more stuff then. I think I could provide you a proper guide on Streams. So if you have anything to get clarified, drop a comment "D

Good Bye! Stay safe!!!




4 Comments