JB Header
Java 8 Filtering and Slicing with Streams Tutorial with examples
Introduction This tutorial explains how to do filtering and slicing in Java 8 Streams using the filter, distinct, limit and skip methods. It assumes that you are familiar with basics of Java 8 Streams APITutorial on Basics of Java 8 Streams API. Streams Filtering & Slicing Basics Java 8 Streams support declarative filtering out of elements along with the ability to slice-off portions of a list. Streams support four operations to achieve this - filter(), distinct(), limit(n) and skip(n). Lets quickly look at what these methods do followed by a java example which uses all of these. Methods in Streams API for filtering and slicing
  1. Filter method: The filter method filters out elements from a given stream. It uses a Predicate function Click to Read Tutorial on Predicate Function instance which it applies to the whole stream and returns a filtered stream containing those elements which match the Predicate. It is an intermediateClick to Read Tutorial explaining intermediate & terminal Stream operations stream operation. Syntax of filter method: <stream-instance>.filter() Returns: java.util.Stream
  2. Distinct Method: The distinct method when applied to a stream, returns a stream instance which has all elements unique/distinct. I.e. every unique element is present only once in the resultant stream. The uniqueness of elements in the resultant stream is determined by the equals & hashcodeClick to Read Tutorial explaining how to override equals() and hashcode() methods implementation in these elements. It is an intermediate stream operation. Syntax of distinct method: <stream-instance>.distinct() Returns: java.util.Stream
  3. Limit(n) method: The limit method puts an upper-limit cap purely based on the number of elements in the stream. A limit of n applied to a stream returns a stream which contains exactly n elements if the original stream had more than or equal to n elements. In case the original stream had less than n elements, and limit of n has been applied on the stream, then there is no affect on the stream elements, i.e. the returned stream is same as the original stream. This method is a short-circuitingClick to Read Tutorial explaining concept of Short-Circuits in Computing intermediate stream operation. Syntax of limit method: <stream-instance>.limit(n) Returns: java.util.Stream of n elements
  4. Skip(n) method: The skip method is complimentary to the limit method. I.e. the skip method returns a truncated version of the original stream such that the first n elements in the list are skipped and the remaining elements are returned in the resulting stream. This method is an intermediate stream operation. Syntax of skip method: <stream-instance>.skip(n) Returns: java.util.Stream of elements post first n elements
The reason limit(n) & skip(n) are complimentary is because given a stream of size k, streams obtained from limit(n) & skip(n) applied on the original stream (where, n<=k) when aggregated together give us the original stream back. While limit(n) gives the first n elements from positions 1 to n; skip(n) gives elements from positions n+1 to k. Thus, joining the streams obtained from limit(n) & skip(n) gives us the original stream back. Java example demonstrating the use of filter, distinct, limit & skip methods
Java example demonstrating the use of filter, distinct, limit & skip methods
//Employee.java
public class Employee{
  private String name;
  private Integer age;
  public Employee(String name, Integer age){
    this.name=name;
    this.age=age;
  } 
  public String getName(){
    return name;
  }
  public void setName(String name){
    this.name=name;
  } 
  public Integer getAge(){
    return this.age;
  } 
  public void setAge(Integer age){
    this.age=age;
  }  
  public String toString(){
    return "Employee Name:"+this.name
      +"  Age:"+this.age;
  }
  @Override
  public boolean equals(Object obj) {
     if (obj == this) {
       return true;
     }
     if (!(obj instanceof Employee)) {
       return false;
     }
     Employee empObj = (Employee) obj;
       return this.age==empObj.age
         && this.name.equalsIgnoreCase(empObj.name);
  }
  @Override
  public int hashCode() {
    int hash = 1;
    hash = hash * 17 + this.name.hashCode();
    hash = hash * 31 + this.age;
    return hash;
  }
}
//FilteringSlicingStreams.java
import java.util.List;
import java.util.Arrays;
import static java.util.stream.Collectors.toList;
public class FilteringSlicingStreams {
 static List<Employee> employeeList=Arrays.asList(
   new Employee("Tom Jones", 45), 
   new Employee("Harry Major", 25),
   new Employee("Ethan Hardy", 65),
   new Employee("Nancy Smith", 15),
   new Employee("Deborah Sprightly", 29),
   new Employee("Dick Hiddleton Sprightly", 44),
   new Employee("Alexander Hick", 19),
   new Employee("Harry Major", 25),
   new Employee("Nancy Smith", 15));
 public static void main(String args[]){
   //filter method
   List<Employee> filteredList= employeeList.stream().filter((Employee e)-> e.getAge() > 24).collect(toList());
   System.out.println("After applying filter method");
   filteredList.forEach(System.out::println);
   //distinct method
   filteredList= filteredList.stream().distinct().collect(toList());
   System.out.println("After applying distinct() method");
   filteredList.forEach(System.out::println);
   //limit method
   filteredList= filteredList.stream().limit(2).collect(toList());
   System.out.println("After applying limit(2) method");
   filteredList.forEach(System.out::println);
   //skip method
   filteredList= filteredList.stream().skip(1).collect(toList());
   System.out.println("After applying skip(1) method");
   filteredList.forEach(System.out::println);
 } 
}
 OUTPUT of the above code
After applying filter() method
Employee Name:Tom Jones  Age:45
Employee Name:Harry Major  Age:25
Employee Name:Ethan Hardy  Age:65
Employee Name:Deborah Sprightly  Age:29
Employee Name:Dick Hiddleton Sprightly  Age:44
Employee Name:Harry Major  Age:25

After applying distinct() method Employee Name:Tom Jones Age:45 Employee Name:Harry Major Age:25 Employee Name:Ethan Hardy Age:65 Employee Name:Deborah Sprightly Age:29 Employee Name:Dick Hiddleton Sprightly Age:44
After applying limit(2) method Employee Name:Tom Jones Age:45 Employee Name:Harry Major Age:25
After applying skip(1) method Employee Name:Harry Major Age:25
Explanation of the java example’s code & output
  • 2 classes are defined in the code above. First is Employee class which consists of 2 attributes - name & age. It also contains equals()& hashcode() methods implemented.
  • Second class is FilteringSlicingStreams which defines a list of 9 Employees using Arrays.asList().
  • In the main() method first the filter() method is called with Predicate lambda defined in such a way that only employees greater than 24 years of age satisfy the condition. As a result the filteredList variable gets a list of Employees with 6 employees in them. I have highlighted the different portions of output with green color for easy readability. There are 6 employee records printed in the output below the line "After applying filter method".
  • Next the filteredList is taken and distinct() method is applied to it. This list of 6 filtered employees is now reduced to 5 with 1 instance of Harry Major aged 25 being removed as it is duplicate. Note that hashcode() & equals()Read tutorial explaining why hashcode & equals are overridden implementation in Employee has been done to make distinct method work correctly. The list of 5 Employees remaining as a result is printed in the output below the line "After applying distinct() method".
  • Next the limit(2) method is applied to the filteredList instance returned after applying distinct. This limits the resultant list to exactly 2 Employee records which are shown in the output below the line "After applying limit(2) method".
  • Lastly the skip(1) method is applied to the filteredList which now contains 2 employees. This causes the resultant stream and list to skip the first Employee in the list(Tom Jones) and we are now left with only 1 Employee in the list(Harry Major). Details of this 1 employee are printed below the output line "After applying skip(1) method".
Summary This wraps-up the tutorial on filtering and slicing of Streams using the filter, distinct, limit & skip methods.