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 -
The reason limit(n) & skip(n) are complimentary is because given a stream of size k, streams obtained from
OUTPUT of the above code
Explanation of the java example’s code & output
Summary
This wraps-up the tutorial on filtering and slicing of Streams using the filter, distinct, limit & skip methods.
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
- 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
- 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
- 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 - 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
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);
}
}
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
- 2 classes are defined in the code above. First is
Employee
class which consists of 2 attributes -name
&age
. It also containsequals()
&hashcode()
methods implemented. - Second class is
FilteringSlicingStreams
which defines a list of 9 Employees usingArrays.asList()
. - In the
main()
method first thefilter()
method is called withPredicate
lambda defined in such a way that only employees greater than 24 years of age satisfy the condition. As a result thefilteredList
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 anddistinct()
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 thathashcode()
&equals()
Read tutorial explaining why hashcode & equals are overridden implementation inEmployee
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 thefilteredList
instance returned after applying distinct. This limits the resultant list to exactly 2Employee
records which are shown in the output below the line "After applying limit(2) method". - Lastly the
skip(1)
method is applied to thefilteredList
which now contains 2 employees. This causes the resultant stream and list to skip the firstEmployee
in the list(Tom Jones) and we are now left with only 1Employee
in the list(Harry Major). Details of this 1 employee are printed below the output line "After applying skip(1) method".
Java 8 Streams API tutorials on JavaBrahman
Streams API - Introduction & BasicsClick to Read tutorial on Streams API Basics Understanding Stream Operations | Intermediate and Terminal OperationsClick to Read Tutorial on Stream Operations Overview Mapping with Streams using map and flatMap methodsClick to Read how Mapping with Java8 Streams works Filtering and Slicing with Streams using filter,distinct,limit,skip methodsClick to Read how Filtering and Slicing with Java8 Streams works Matching with Streams using allMatch,anyMatch,noneMatch methodsClick to Read tutorial on matching with Streams API Stream API's findFirst,findAny methods' tutorialClick to Read tutorial on findFirst() and findAny() methods of Streams API 'Peeking' into a running Stream with Stream.peek() methodClick to Read tutorial on Stream.peek() method Creating Infinite Streams with iterate\generate methodsClick to Read tutorial on Creating Infinite Streams Reducing Streams using Streams.reduce methodClick to Read tutorial on Reducing Streams
Streams API - Introduction & BasicsClick to Read tutorial on Streams API Basics Understanding Stream Operations | Intermediate and Terminal OperationsClick to Read Tutorial on Stream Operations Overview Mapping with Streams using map and flatMap methodsClick to Read how Mapping with Java8 Streams works Filtering and Slicing with Streams using filter,distinct,limit,skip methodsClick to Read how Filtering and Slicing with Java8 Streams works Matching with Streams using allMatch,anyMatch,noneMatch methodsClick to Read tutorial on matching with Streams API Stream API's findFirst,findAny methods' tutorialClick to Read tutorial on findFirst() and findAny() methods of Streams API 'Peeking' into a running Stream with Stream.peek() methodClick to Read tutorial on Stream.peek() method Creating Infinite Streams with iterate\generate methodsClick to Read tutorial on Creating Infinite Streams Reducing Streams using Streams.reduce methodClick to Read tutorial on Reducing Streams