Java Streams: An Intro to Filter, and Map

Java Streams: An Intro to Filter, and Map

Java is one of the most popular programming languages in the world today. If we take a look at the number of jobs posted by the programming language, we find something like this.

Image Source: Coding Dojo

We can see that Java still dominates today. It is because, with every new version of Java, there are tons of improvements, it's robust, has many tools and backed by enterprise business. Little promotion, by the author of this article: If you want to code efficiently and get a well-paid job, you may opt for a Node.JS training course that can enhance your learnings to a great level.

With the leap forward from Java 7 to Java 8, we have again seen a lot of improvements. Java 8 incorporates functional programming constructs. Moreover, you will also find the support for lambda expressions. Java 8 has a marvelous Streams API that enables programmers to deal with sequences of elements like lists and array like never before.

In this article, you’re going to learn about the creation of streams. After that, I will show you how you can transform various data streams with the help of methods like map, filter, and reduce.

The first task is to Create a Stream

The stream is a sequence of items and numerous methods are available for creating one. However, we will keep it simple for this tutorial. We will use lists and arrays for the creation of streams. Every single class with Java 8 come up with java.util.The collection has an inbuilt stream method. It enables you to turn its instances into Stream Objects, which makes it incredibly easy to turn lists into streams in Java 8.

Take a look at how you can convert an Array into a Stream.

// Create an ArrayList
List<Integer> myList = new ArrayList<Integer>();
myList.add(1);
myList.add(5);
myList.add(8);

// Convert it into a Stream
Stream<Integer> myStream = myList.stream();

Code Source: GitHub

This way, you can access the stream not just with Array, but any other collection, such as List, Set, Map and other. In case you are more comfortable with arrays, for demonstrational purposes:

// Create an array
Integer[] myArray = {1, 5, 8};

// Convert it into a Stream
Stream<Integer> myStream = Arrays.stream(myArray);

Code Source: GitHub

Time to look at the Map Method

After the creation of a stream object, you are now eligible to use different types of methods for transforming it into yet another Stream Object. Why would we need that? There are certain situations, where you want to process every element in your collection and do something with it.

Here, a lambda expression is enough as the single argument. We can use it to convert all individual elements into streams. The return value, a new Stream object, will include changed items.

Here is a demonstration to give you a better understanding. Below is the code that converts the array into a Stream.

String[] myArray = new String[]{"bob", "alice", "paul", "ellie"};
Stream<String> myStream = Arrays.stream(myArray);

Code Source: GitHub

After the first step, we will be calling the map method, passing a lambda expression. It allows the program to convert a string into uppercase with a single argument.

Stream<String> myNewStream = 
myStream.map(s -> s.toUpperCase());

Code Source: GitHub

The returned Stream Object consists of the changed strings. We can use the toArray method for converting it into an array.

String[] myNewArray =
myNewStream.toArray(String[]::new);

Code Source: GitHub

Now, you have an array of strings that are in uppercase. I hope you realize how this style of coding can increase the readability of codes.

The Filter Method

We used the map method in the previous section to process every single item to a Stream Object. However, you might not want to do that all the time. There are times when you want to work with subsets of elements. For that purpose, we have a filter method.

Just like in the map method, we use a lambda expression as a single argument. However, you will get a **boolean value*** in return in the filter method. It decides whether the processed element should comprise the resulting Stream Object or not.

Below is an example of the creation of a subset from an array of string, whose length exceeds four characters.

Arrays.stream(myArray)
.filter(s -> s.length() > 4)
.toArray(String[]::new);

Code Source: GitHub

The above code looks clearer than before. The majority of developers prefer using functional codes like above, as it does not require a program to save references to intermediate Stream Objects.

The reduction operations

The reduction operation makes it possible to compute a result with all the items in a stream. We also call it a termination operation because we can find it at the end of every chain of Stream methods. Previously, we used termination operation, toArray method, as it converted a Stream object into an array.

Java 8 has many reduction operations, such as sum, average, and count. It allows the developers to perform calculations on stream objects.

Here is a simple example of the arithmetic operation in Java 8.

int myArray[] = { 1, 5, 8 };
int sum = Arrays.stream(myArray).sum();

Code Source: GitHub

However, you need to use the reduction method for sophisticated reduction operations. Reduce method demands two arguments.

  • An identity element
  • A lambda expression

An identity element is a type of component that does not hinder the reduction operation results. For instance, the identity element “1” could be the representation of the product of all the items in a stream of numbers.

In case of a lambda expression that you pass, it must be able to handle two inputs:

  • A partial reduction operation result
  • The stream’s current element

Here is a sample code to help you understand

String[] myArray = { "this", "is", "a", "sentence" };
String result = Arrays.stream(myArray)
.reduce("", (a,b) -> a + b);

Code Source: GitHub

Final thoughs

Keep in mind that I’ve not covered in-depth applications of filter and map in this tutorial. However, it does not mean that I’ve provided incomplete information in this article. It includes enough info for you to get started with map, filter, and reduce methods.

With that said, there is a lot for you to explore regarding the use of filter and map. In case of large streams, you should go with parallel streams, instead of serial streams. Parallel streams might be useful in some use cases, but the performance gain is not in fact linear. I hope you’ve gotten value from this article. If I’ve missed something or if you want to add more value to this piece of content, feel free to leave a comment below. I will be happy to read your opinions.


Related Posts