Java Stream Intermediate Operations Examples

In this tutorial, we will learn Java 8 Stream intermediate operations with examples.

Stream operations are divided into intermediate and terminal operations.

As intermediate operations return another stream as a result, they can be chained together to form a pipeline of operations. Terminal operations can not be chained together.

Check out Java Stream Terminal Operations Examples tutorial.

Java Stream Intermediate Operations

  • filter()
  • map()
  • flatMap()
  • distinct()
  • sorted()
  • peek()
  • limit()
  • skip()
Let's understand the above Stream intermediate operations with an example.

filter()

The Java Stream filter() can be used to filter out elements from a Java Stream. The filter method takes a Predicate that is called for each element in the stream. If the element is to be included in the resulting Stream, the Predicate should return true. If the element should not be included, the Predicate should return false.

Here is an example of calling the Java Stream filter() method:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Tester {
   public static void main(String[] args){
        List<String> lines = Arrays.asList("java", "c", "python");

        List<String> result = lines.stream()       // convert list to stream
                .filter(line -> !"c".equals(line)) // we dont like c
                .collect(Collectors.toList());     // collect the output and convert streams to a List

        result.forEach(System.out::println);  
    }
}

Output:

java
python

Using filter() method to filter List of string objects:

map()

The Java Stream map() method converts (maps) an element to another object. For instance, if you had a list of strings it could convert each string to lowercase, uppercase, or to a substring of the original string, or something completely else. 

Here is a Java Stream map() example: 

If you have a List of String and you want to convert that to a List of Integer, you can use map() to do so.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
 
public class Main 
{
    public static void main(String[] args) 
    {
        List<String> listOfStrings = Arrays.asList("1", "2", "3", "4", "5");
         
        List<Integer> listOfIntegers = listOfStrings.stream()
                        .map(Integer::valueOf)
                        .collect(Collectors.toList());
         
        System.out.println(listOfIntegers);
    }
}

Output:

[1, 2, 3, 4, 5]

flatMap()

The Stream.flatMap() function, as the name suggests, is the combination of a map and a flat operation. This means you first apply the map function and then flatten the result. 

To understand what flattening a stream consists in, consider a structure like [ [1,2,3],[4,5,6],[7,8,9] ] which has "two levels". It's basically a big List containing three more List. Flattening this means transforming it in a "one level" structure e.g. [ 1,2,3,4,5,6,7,8,9 ] i.e. just one list.

For example: In the below program, you can see that we have three lists that are merged into one by using a flatMap() function.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args)
    {
        List<Integer> evens = Arrays.asList(2, 4, 6);
        List<Integer> odds = Arrays.asList(3, 5, 7);
        List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11);
        List<Integer> numbers = Stream.of(evens, odds, primes)
                .flatMap(list -> list.stream())
                .collect(Collectors.toList());
        System.out.println("flattend list: " + numbers);
    }
}

Output:

flattend list: [2, 4, 6, 3, 5, 7, 2, 3, 5, 7, 11]

distinct()

The Java Stream distinct() method is a non-terminal operation that returns a new Stream that will only contain the distinct elements from the original stream. Any duplicates will be eliminated. 

Here is an example of the Java Stream distinct() method:
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args)
    {
        List<String> stringList = new ArrayList<>();

        stringList.add("one");
        stringList.add("two");
        stringList.add("three");
        stringList.add("one");

        Stream<String> stream = stringList.stream();

        List<String> distinctStrings = stream
                .distinct()
                .collect(Collectors.toList());

        System.out.println(distinctStrings);
    }
}

Output:

[one, two, three]

limit()

The Java Stream limit() method can limit the number of elements in a stream to a number given to the limit() method as a parameter. The limit() method returns a new Stream that will at most contain the given number of elements. 

Here is a Java Stream limit() example:

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args)
    {
        List<String> stringList = new ArrayList<>();

        stringList.add("one");
        stringList.add("two");
        stringList.add("three");
        stringList.add("one");

        Stream<String> stream = stringList.stream();

        stream.limit(2)
                .forEach( element -> { System.out.println(element); });
    }
}

Output:

one
two

peek()

The Java Stream peek() method is a non-terminal operation that takes a Consumer interface as a parameter. The Consumer will get called for each element in the stream. The peek() method returns a new Stream that contains all the elements in the original stream.

The purpose of the peek() method is, as the method says, to peek at the elements in the stream, not to transform them. Keep in mind that the peek method does not start the internal iteration of the elements in the stream. You need to call a terminal operation for that. 

Here is a Java Stream peek() example:
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args)
    {
        Stream.of("one", "two", "three", "four")
                .filter(e -> e.length() > 3)
                .peek(e -> System.out.println("Filtered value: " + e))
                .map(String::toUpperCase)
                .peek(e -> System.out.println("Mapped value: " + e))
                .collect(Collectors.toList());
    }
}

Output:

Filtered value: three
Mapped value: THREE
Filtered value: four
Mapped value: FOUR
As peek()‘s Javadoc page says: “This method exists mainly to support debugging, where you want to see the elements as they flow past a certain point in a pipeline“.

Related Tutorials

Comments