Home Java Stream API: The Hero Without a Cape

Stream API: The Hero Without a Cape

Published: Last Updated on 4 comments

Hey Tea Lovers! In this post, we will be talking about an unsung hero of the Java world, the Stream API which was added to Java 8 and has changed the way we do programs in java and how! It added neatness as well as made the program more readable. It helps you do functional programming in Java. Without any further ado, let us read more about this jewel.


I would be happy to connect with you guys on social media. It’s @coderstea on TwitterLinkedinFacebook, Instagram, and YouTube.

Please Subscribe to the newsletter to know about the latest posts from CodersTea.


What is Stream API

The Stream API, included in Java 8, is utilized for processing collections of objects. It is the flow of Objets on which various methods get applied in the pipeline to have the result. Simply put, it flows through the given Collection<Object> and applies the different methods on the Object to aggregate them into the desired result without affecting the original Object.

What Stream Provides

Stream doesn’t store anything instead, it operates on the given CollectionArray or I/O (yes you can use it on I/O) Without changing the original data, it applies the methods to the data. Lazy evaluation helps to add multiple intermediate operations without actually utilizing them at the moment of building it. It gets evaluated only after our terminal operation. The Stream API also adds neatness to the code to make it more readable. And yes, Functional Programming is a key feature.

Prerequisites to Start Using Stream API

Stream allows you to do functional programming in Java. This means you should be comfortable with functional interfaces and lambda. Don’t worry, You just need the basics of it, which you can do with the help of this post, “Be More Functional With Java’s Functional Interfaces”. If you know these well, nobody will stop you from implementing the Stream APIFor the examples used in this post, you can find the code on GitHub here or the full project here. And yes, fill your cup of tea, start sipping and see more about this hero.

How to use Stream API

We can do this in multiple ways. Such magic tricks are,

  1. Collection’s stream() and parallelStream() methods
  2. Via Arrays.stream(Object[])
  3. One of Stream’s static factory methods such as,
    1. Stream.of(Object[])
    2. IntStream.range(int, int) 
    3. Stream.iterate(Object, UnaryOperator)
  4. Streaming the line of a file by BufferedReader.lines()
  5. Streams of random numbers can be obtained from Random.ints()

1st and 2nd are what we use most often. For our discussion, we will be sticking to the Collection’s stream method. For Example,

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
list.stream()
	// multiplying each number by 2
	.map(n -> n * 2)
	//taking forward only even numbers
	.filter(n -> n % 2 == 0)
	//printing each even number
	.forEach(n -> System.out.println(n));Code language: PHP (php)

Stream Pipeline Operations

We can perform two operations on a Stream pipeline

  • Intermediate Operation
  • Terminal Operation

Intermediate Operation transforms or filters the object in the preceding pipeline. These methods are nothing but the functional interfaces we discussed in our previous post. You should get familiar with them to easily understand this operation without any trouble. Stream won’t execute intermediate operations unless a Terminal Operation gets called.

Terminal Operation is an indication for the Stream to start the pipeline. Once we call the terminal operation pipeline ends and it returns the desired result. After the terminal operation, we can’t use an intermediate operation since the pipeline has ended. It can only be called once at the end of the pipeline. However, you can again start the stream if the terminal operation returns a collection. Which I highly oppose doing.

You can pretty much everything inside a single stream pipeline only.

Now, let us see these operations one by one.

Stream API Intermediate Operations

In the Stream pipeline, we can have multiple intermediate operations that transform or filter the data which will be flowing toward the next pipe without affecting the actual data on the Collection. These operations return the Stream of the desired result instead of the actual result i.e Stream<T>. With this, we can add more intermediate operations without breaking the Stream pipeline. We will be talking about the map and filter in this post and others in another part. map and filter are the ones you will be needing most of the time.

These methods are applied one by one to the elements in the pipeline and not all at once.

Stream API map()

Think of it as a transforming function, which transforms the given object into another. It accepts a Function<T> as a parameter, which takes the element in the stream as input, performs some operation, we tell it to do, and returns Stream the resulting object. Learn more about Function it here.

If we look at our previous example, it is multiplying each number by 2. We can have another map that can add 2 to the multiplied number and then another one to convert it to another object. and then another one and so on, you get the idea.

list.stream()
        // 1. multiplying each number by 2
        .map(n -> n * 2)
        // 2. Converting to string.
        .map(n -> "coderstea.in-Post No : " + n)
        //3. Now you will be working on the
        //stream of String
        //4. we add another string to the previous
        .map(string -> string + ". Another String")
        //5. print the end result
        .forEach(System.out::println);Code language: PHP (php)

In the above example look at how we transformed a list of Integer to the String. Let’s break down it.

  1. Multiplying each number by 2. So 1 becomes 2, 4 becomes 8
  2. We have attached the number to a string resulting in a string object.
  3. The previous map was made the Stream<Integer> to Stream<String> due to the return type of string.
  4. We again attached another string to perform some operations.
  5. Finally printing the results. Which looks like,

Output:

coderstea.in-Post No : 2. Another String
coderstea.in-Post No : 4. Another String
coderstea.in-Post No : 6. Another String
coderstea.in-Post No : 8. Another String
coderstea.in-Post No : 10. Another String
coderstea.in-Post No : 12. Another String
coderstea.in-Post No : 14. Another String
coderstea.in-Post No : 16. Another String
coderstea.in-Post No : 18. Another String
coderstea.in-Post No : 20. Another StringCode language: JavaScript (javascript)

Stream API filter()

The filter, as the name suggests, filters out the elements before it reaches the next pipe. Simply put, if the element satisfies the condition it allows it to pass through otherwise it won’t allow for the next operation. It takes an Predicate as a parameter. Know about Predicate here.

long count = list.stream()
        // 1. Need only even numbers
        .filter(n -> n % 2 == 0)
        // 2. Checking if the Number is
        // greater than 5
        .filter(n -> n > 5)
        //3. multiplying the number by 5
        // just to show how we can use multiple
        // Intermediate operation together
        .map(n -> n * 5)
        // 4. Any number less than 50
        .filter(n -> n < 50)
        // Counting how much elements
        // survived teh pipeline
        .count();
System.out.println("Total " + count + " numbers survived the storm");Code language: PHP (php)

God, so many filters. let’s break this down, shall we?

  1. Take only even numbers ahead.
  2. Forward only those numbers which are greater than 5
  3. Multiply the number by 5. Again, just to show you can have multiple Intermediate operations in a single Stream pipeline.
  4. Allow numbers that are less than 50.
  5. Finally, count (Terminal Operation) how many survived after this much filtering?

Output:

Total 2 numbers survived the storm

Stream API Terminal Operation

Till now we have seen the operations which perform something in the pipe and return the stream. In the end, we will be needing a final result, which is not a stream, don’t we? That’s where Terminal Operation comes in. It does not only give the desired result but also starts the Stream. As I said, Stream is lazy, it won’t do anything, no matter how many intermediate operations we add to the pipeline, until and unless it sees its end, the terminal operation.

You cant use the same stream after it was closed by a terminal operation. Otherwise, it will throw IllegalStateException: stream has already been operated upon or closed. You have to start a new stream

The terminal operations we will be using for our examples are forEach and count. Let us examine them and a few others.

Stream API forEach()

This iterates over each element passed by the preceding intermediate operation. It takes input but has a void return value. It takes Consumer as a parameter(more on Consumer). Use this if you want to do something without returning anything. We have used it for printing the numbers.

list.stream()
        // square of each number
        .map(n -> n * n)
        //prints each element
        .forEach(n -> System.out.print(" " + n));Code language: PHP (php)

count()

As the name suggests, it is used for counting the elements reached to the end. Like in the filter example, counting the number who satisfied all the filter’s conditions.

long evenAndLt5Count = list.stream()
        // even numbers less than 5s
        .filter(n -> n < 5 && n % 2 == 0)
        .count();
System.out.println(evenAndLt5Count);Code language: PHP (php)

collect()

I use this more often than any other terminal operation. It allows you to create the Collection form of the elements of the stream after processing them. These Collection can be ListSet or Map. The Collection includes elements that passed through the last pipe.

List<Integer> processedList = list.stream()
        // multiplying by 5
        .map(n -> n * 5)
        // numbers less than 30
        .filter(n -> n < 30)
        //add  +2
        .map(n -> n + 2)
        // give the list of processed numbers
        .collect(Collectors.toList());
System.out.println("processed List is \n " + processedList);Code language: PHP (php)

In the pipeline, we multiplied the number by 5, then filtered numbers less than 30 and added 2. And after all the elements are done process, we collect them into the list.

processed List is [7, 12, 17, 22, 27]Code language: CSS (css)

The Last Sip

We have studied what is Stream API in java, how to obtain it, how to operate it, use it. This post is kind of like an introductory post for the Stream API. There are so many diamonds in the Stream mine, which we will be mining in the next post. I highly recommend you check out “Be More Functional With Java’s Functional Interfaces” for a better understanding of the Stream API operation. You can find the code on GitHub here or the full project here.

See you in the next post. HAKUNA MATATA!!!


I would be happy to connect with you guys on social media. It’s @coderstea on TwitterLinkedinFacebook, Instagram, and YouTube.

Please Subscribe to the newsletter to know about the latest posts from CodersTea.


Subscribe
Notify of
guest
4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Ads
Ads
Ads

@2023 All Right Reserved. Designed and Developed by CodersTea

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More