JavaFunctional streams

Filtering elements

The filter operation

The filter operation is an intermediate operation which takes a predicate and returns a new stream consisting of the elements that match the given predicate (the predicate returns true for these elements).

It filters elements according to the given predicate

The filter operation is one of the most used operations with streams.

Let's see an example. A list of prime numbers is given:

List<Integer> primeNumbers = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31);

We'd like to create a new list consisting of prime numbers that belong to the range from 11 to 23 (inclusively).

List<Integer> filteredPrimeNumbers = primeNumbers.stream() // create a stream from the list
        .filter(n -> n >= 11 && n <= 23) // filter elements
        .collect(Collectors.toList());   // collect elements in a new list

The filteredPrimeNumbers list is:
[11, 13, 17, 19, 23]

The method filter takes an instance of the generic predicate. It's possible to instantiate this predicate and pass it to the filter method.

Predicate<Integer> between11and23 = n -> n >= 11 && n <= 23; // instantiate the predicate

List<Integer> filteredPrimeNumbers = primeNumbers.stream() // create a stream from the list
        .filter(between11and23)        // pass the predicate to the filter method
        .collect(Collectors.toList()); // collect elements in a new list

Of course, the result is the same as before.

Multiple filters

In some cases, two or more filter operations are used together. It may be useful to separate a complex logic or when we should filter stream, then process it by other methods and then filter again.

Let's assume we have a list of programming languages (strings). Also, the list has empty strings. Suppose, the languages cannot be repeated in the list.

List<String> programmingLanguages = Arrays.asList("Java", "", "scala", "Kotlin", "", "closure");

We'd like to count how many programming languages start with an upper letter.

long count = programmingLanguages.stream()
        .filter(lang -> lang.length() > 0) // consider only non-empty strings
        .filter(lang -> Character.isUpperCase(lang.charAt(0)))
        .count(); // count suitable languages

The count is 2 ("Java", "Kotlin").

This two filter operations can be replaced with one operation that takes a complex predicate, but this code is less readable:

filter(lang -> lang.length() > 0 && Character.isUpperCase(lang.charAt(0)))

So, the filter is a simple but very useful operation.

Note, if you use IntStream, LongStream or DoubleStream it takes an object of IntPredicate, LongPredicate or DoublePredicate type respectively.

How did you like the theory?
Report a typo