Sunday, May 1, 2016

Stream Interface filter method

Stream Interface filter method

In previous post we saw the data setup. We will use that data to understand all the Stream interface’s methods.

First we will start off with method filter().  As the name suggests it filters the Stream. Before we understand how this method works let us see the code that we write prior to Java 8. After that we will write the same code in elegant way in Java 8.

As we saw in previous post we have some different classes and enums. Gender and Grade as enums and Address, Name and Student as classes.  We are presented a List<Student> which holds Student objects.

We will write a method that will return us number of Students who live in
city NYC and favorite number > 30.

     List<Student> students = StudentDataSet.dataSet();
     int total = 0;
     for(final Student student : students){
           if(student.address().city().equals("NYC")
                && student.favoriteNumber() > 30){
                total = total + 1;
           }
     }

The above code works well as per the requirement that we setup before. But before writing this solution we had to think how to approach this solution. So we iterated the List<Student> using the enhanced for loop and placed a condition. If the condition passed, then we increment the counter.

As we have seen earlier that Streams support internal iteration we so do not need to write any loops for it. Let us see how code in Java 8 looks like.

     long total =
                students.stream()
                .filter(s-> s.address().city().equals("NYC")
                           && s.favoriteNumber() > 30)
                .count();

As we know streams have support for internal iteration it is easy to focus on use case rather than iteration.

Let us now see how the solution with stream works.



Filter method of Stream interface accepts the Predicate.

To learn more about Predicate read here Predicate Functional Interface Part 1 & Part 2, Predicate AND, Predicate OR, Predicate NEGATE and reusing Predicates.

Predicate is Functional interface provided in java.util.function package. 

This operation accepts a Predicate and returns a stream that matches the given Predicate. 

Suppose you can create a Stream of Student by Gender, city or country or we can combine different Predicate together into one.

Let us combine different predicates together.

/**
 * Returns a {@link Predicate} that matches the given
 * {@link Address#city()}.
 * */
public static
Predicate<Student> cityFilter(final String city) {
     return s -> s.address().city().equals(city);
}

/**
 * Returns a {@link Predicate} that matches the
 * given {@link Gender}.
 * */
public static
Predicate<Student> genderFilter(final Gender gender) {
     return s -> s.gender().equals(gender);
}

/**
 * Returns a {@link Predicate} that matches the
 * given {@link Address#country()}.
 * */
public static
Predicate<Student> countryFilter(final String country) {
     return s -> s.address().country().equals(country);
}

We can use the above predicates as below by chaining them together.  

final Predicate<Student> cityAndCountry=
                     cityFilter("NYC").and(countryFilter("USA"));
          
final long count =
                students.stream()
                       .filter(cityAndCountry)
                       .count();


We will use this method often to filter the stream and them perform operations on filtered stream. 

Ads Inside Post