Friday, June 10, 2016

Stream Interface forEach method

Stream Interface forEach method.

Streams, a new feature in Java 8 that deals with pipelining and data processing operations with fluent API.

What that means is as Collections are data storage mechanisms Streams are data processing mechanisms. We have covered some ground in Streams like we know what Streams are? We saw how it allows us to write code declaratively. We do not need to worry about any kind of loops we just worry of our use-case and write code as story.

We also saw what is Intermediate operation (operation that returns Stream<T>) and what is Terminal operation (operation that returns Non-Stream result).

In previous posts we did data setup and we saw how to filter the Stream using filter() method. In this post we will talk about forEach method.

What is forEach method?


Yes, those are stairs. We all have seen one. What does that signify? Well, while climbing stairs what we do? We see if there are more stairs available then climb stairs or else walk. That is what forEach is all about. If the element is available, then iterate else stop.

Normally we have enhanced for loops or for each loops as below: Click here to see the data setup.

      final List<Student> students = StudentDataSet.dataSet();
     for (final Student student : students) {
           System.out.println(student);
     }

What is really going on? You are iterating(climbing) through the List(ladder) and printing the elements. Don’t you think this is overkill to print the elements? Why use for loop? Till now we didn’t had other way the iterate through the Collection but now we do have a great way called Streams.

Let us perform above task in Java 8.

     /**
     * Performs an action for each element of this stream.
     * No guarantee on element's order.
     */
students.stream()
             .forEach(new Consumer<Student>() {
                  @Override
                  public void accept(Student student) {                                           System.out.println(student);
                  }
             });
     
     
Ok great. What happened?


No, this is not the final solution. Final solution is very elegant. The motive of Inner class in forEach method is to understand that a Functional interface is here to help you.

Below is the code that displays the forEach method of Stream interface.

     students.stream()
             .forEach(student -> System.out.println(student));

Above solution does not have for loops, no inner class, no mutable data. Isn’t it a beauty?

Now let us look at the first solution again.
    /**
     * Performs an action for each element of this stream.
     * No guarantee on element's order.
     */
students.stream()
             .forEach(new Consumer<Student>() {
                  @Override
                  public void accept(Student student) {
                                                                                                System.out.println(student);
                  }
             });

The anonymous inner class Consumer is a functional interface. Read about Functional interfaces here. Read more about Consumer interface here.

Consumer interface represents an operation that accepts single input argument and returns no result. Isn’t that what we need? ForEach loop accepts the current element and process it and does not return anything. This matches our criteria.

·         Now as Consumer interface is Functional interface we can pass Lambda operator to it. So we can write it like this:
students.stream().forEach((Student student) ->                                        System.out.println(student));


·         But in functional interface we can remove the type(Student) of parameter as compiler can reference that target type will be Student. If you are using some method that accepts two different types of parameters, then you need to explicitly provide the type. We will talk about this later. So we can again make our code better.

      students.stream()
              .forEach((student) -> System.out.println(student));

·         If there is single parameter then we can eliminate the brackets outside the parameter too.
students.stream()
     .forEach(student -> System.out.println(student));

·         Excellent isn’t it? You can use method reference here too. We will talk about it later.
students.stream()
     .forEach(System.out::println);

Now you compare the code that we wrote with for-each loop and the one with method reference or lambda operator.

Awesome isn’t it. But remember one thing forEach method of Stream interface does not guarantee the that elements are processed in sequential order.

To summarize use forEach method in Stream used to do some activity while iterating the data source in our case the data source is collection.

In next post we will see allMatch method of Stream interface. It returns true if given condition is true for all elements in Stream and returns false if atleast once given condition is false. It accepts Predicate (functional interface) as argument.

If there is anything wrong or needs improvement or have any doubts, please post in comments below. I will reply them. Thanks for reading.

Ads Inside Post