Java Streams Intermediate Operations with Examples

In this post, we will learn Java Streams Intermediate Operations like Filter, Map, FlatMap, Limit, Peek, Skip, Distinct, and Sorted. In a stream pipeline, we have intermediate operations and at the end of the stream, we have terminal operations. We do most of the work like filtering, transforming, limiting, etc. as intermediate operations. Let’s start to learn of these intermediate operations with examples.

Java Streams Intermediate Operations

Let’s start with an example that covers filter, limit, map, and the peek.

Java Streams Peek, Filter, Map, and Limit Example

filter(): It filters the elements based on a given rule inside the filter method.

limit(): It limits the execution of the elements after reaching the limit number.

peek(): We can use the peek function for debugging purposes.

map()It does the transformation for the elements. For example, we can make a text uppercase or lower case with map operation.

Let’s see all of them in the below example.

public class StreamPeek {
    List<Integer> numbers = new ArrayList<>();

    @BeforeEach
    public void setup() {
        //Another method: Collections.addAll(numbers, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        numbers.add(5);
        numbers.add(6);
        numbers.add(7);
        numbers.add(8);
        numbers.add(9);
        numbers.add(10);
    }

    @AfterEach
    public void tearDown() {
        numbers.clear();
    }

    @Test
    public void streamPeekTest() {
        System.out.println("Stream operations are starting!");
        
        numbers.stream()
            .peek(number -> System.out.println("Filter operation for number: " + number)) //Peek is used for debugging purposes.
            .filter(number -> number % 2 == 1) //Filter the odd numbers
            .limit(4) //After 4th element stop the stream. Process first 4 element.
            .peek(number -> System.out.println("Map operation for number: " + number)) //Peek is used for debugging purposes.
            .map(number -> number * 2) //Transform the number to number*2
            .forEach(number -> System.out.println("Result of stream: " + number)); //Print the results.
        
        System.out.println("Stream operations finished!");
    }
}

Output

As seen in the below screenshot, the odd numbers filtered up to the 4th odd number which is 7, and then the stream pipeline terminated. We used the peek() operation for debugging purposes with print statements and with the map() operation we multiplied the elements by 2.

java streams intermediate operations

Java Streams FlatMap Example

If you have a list of lists then you can use flatMap() to convert the list of lists to a list. Better to understand flatMap with an example. We have 3 Integer lists and one list holds these 3 integers lists. If we want to flatten the list which holds 3 integer lists, we need to use flatMap(). Let’s code it and see how it works.

public class StreamFlatMap {
    List<Integer>       numbersList1         = new ArrayList<>();
    List<Integer>       numbersList2         = new ArrayList<>();
    List<Integer>       numbersList3         = new ArrayList<>();
    List<List<Integer>> listOfAllNumberLists = new ArrayList<>();

    @BeforeEach
    public void setup() {
        numbersList1.add(1);
        numbersList1.add(2);
        numbersList1.add(3);
        numbersList2.add(4);
        numbersList2.add(5);
        numbersList2.add(6);
        numbersList3.add(7);
        numbersList3.add(8);
        numbersList3.add(9);
        numbersList3.add(10);
        listOfAllNumberLists.add(numbersList1);
        listOfAllNumberLists.add(numbersList2);
        listOfAllNumberLists.add(numbersList3);
    }

    @Test
    public void flatMapTest() {
        listOfAllNumberLists.stream()
            .flatMap(Collection::stream)
            .filter(number -> number > 8)
            .peek(number -> System.out.println("Filtered number: " + number))
            .map(number -> number * number)
            .forEach(System.out::println);
    }
}

As you can see below the screenshot, IntelliJ also shows and helps us to show how we flatten the Stream<List<Integer>> to Stream<Integer> by using flatMap().

java stream flatMap

We will filter the numbers which are bigger than 8 and then multiply them by themselves and print the results with forEach(). The code filters 9 and 10 and then it prints 81 and 100. Let’s see the output. 

Output

flatmap in streams

Java Streams Skip Example

By using skip operation, we will skip the number of elements in the stream pipeline. Let’s see this in action with some code.

In the below code, the skip() operation skips the first 7 elements and then starts to apply stream pipeline for the rest of the elements.

public class StreamSkip {
    List<Integer> numbers = new ArrayList<>();

    @BeforeEach
    public void setup() {
        //Another method: Collections.addAll(numbers, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        numbers.add(5);
        numbers.add(6);
        numbers.add(7);
        numbers.add(8);
        numbers.add(9);
        numbers.add(10);
    }

    @AfterEach
    public void tearDown() {
        numbers.clear();
    }

    @Test
    public void streamSkipTest() {
        System.out.println("Stream operations are starting!");
        numbers.stream()
            .skip(7) //Skip the first 7 element
            .peek(number -> System.out.println("Map operation for number: " + number)) //Peek is used for debugging purposes.
            .map(number -> number * 2) //Transform the number to number*2
            .forEach(number -> System.out.println("Result of stream: " + number)); //Print the results.
        System.out.println("Stream operations finished!");
    }
}

Output

The code skips the first 7 numbers, then starting with 8, it starts to process the stream pipeline. With peek() operation, it prints out some details for debugging purposes, with map(), it transforms the element to (element * 2), and with forEach() terminal operation it prints out the results.

java streams skip operation

Java Streams Sorted Examples

We use sorted() method to sort the stream pipeline elements. By default, the sort operation is done in natural order like Ascending Sort way. If we want to sort in reverse order (Descending Sort), then we need to use the sorted(Comparator.reverseOrder()) operation. I will show these cases in the below example.

First Example

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class StreamSorted {
    List<Integer> numbers = new ArrayList<>();

    @BeforeEach
    public void setup(TestInfo testInfo) {
        System.out.println("Test name: " + testInfo.getDisplayName());
        numbers.add(5);
        numbers.add(8);
        numbers.add(3);
        numbers.add(7);
        numbers.add(2);
        numbers.add(6);
        numbers.add(1);
        numbers.add(10);
        numbers.add(9);
        numbers.add(4);
    }

    @AfterEach
    public void tearDown() {
        numbers.clear();
        System.out.println("");
    }

    /**
     * Below the stream first limits 4 filtered elements and then sorts them and then stream pipeline works.
     */
    @Test
    @Order(1)
    public void streamSortedTest() {
        numbers.stream()
            .peek(number -> System.out.println("Filter operation for number: " + number)) //Peek is used for debugging purposes.
            .filter(number -> number % 2 == 1) //Filter the odd numbers
            .limit(4) //After 4th element stop the stream. Process first 4 element.
            .sorted() //By default, sorted works as natural order of Ascending Sort. After sorting, stream pipeline continues.
            .peek(number -> System.out.println("Map operation for number: " + number)) //Peek is used for debugging purposes.
            .map(number -> number * 2) //Transform the number to number*2
            .forEach(number -> System.out.println("Result of stream: " + number)); //Print the results.
    }

    //Second and Third examples can be copy pasted here which you can see after first example.
}

In the first example, the code:

  • Prints the debugging texts with peek().
  • Filters the odd numbers.
  • With limit(4), when the 4th odd number is filtered which is “1”, it does not continue to do operations for other elements.
  • Then, sorts these 4th filtered odd numbers in Ascending Order.
  • Prints the debugging texts with peek(),
  • Transform the elements to (elements*2).
  • Prints the results with forEach().

java streams intermediate operations sorted

Second Example

/**
 * Natural sort is Ascending Sort
 */
@Test
@Order(2)
public void streamNaturalOrderSortTest() {
    numbers.stream()
        .peek(number -> System.out.println("Filter operation for number: " + number)) //Peek is used for debugging purposes.
        .filter(number -> number % 2 == 1) //Filter the odd numbers
        .sorted(Comparator.naturalOrder()) //Natural order of sorting. (Ascending Sort)
        .limit(4) //After 4th element stop the stream. Process first 4 element.
        .peek(number -> System.out.println("Map operation for number: " + number)) //Peek is used for debugging purposes.
        .map(number -> number * 2) //Transform the number to number*2
        .forEach(number -> System.out.println("Result of stream: " + number)); //Print the results.
}

In the second example, the code:

  • Prints the debugging texts with peek().
  • Filters the odd numbers.
  • Then, sorts all elements with Natural Order which is Ascending Order.
  • With limit(4), when the 4th odd number is filtered which is “1”, it does not continue to do operations for other elements.
  • Prints the debugging texts with peek(),
  • Transform the elements to (elements*2).
  • Prints the results with forEach().

sorted operation in streams

Third Example

/**
 * Reverse sort is Descending Sort
 */
@Test
@Order(3)
public void streamReverseOrderSortTest() {
    numbers.stream()
        .peek(number -> System.out.println("Filter operation for number: " + number)) //Peek is used for debugging purposes.
        .filter(number -> number % 2 == 1) //Filter the odd numbers
        .sorted(Comparator.reverseOrder()) //Reverse order of sorting. (Descending Sort)
        .limit(4) //After 4th element stop the stream. Process first 4 element.
        .peek(number -> System.out.println("Map operation for number: " + number)) //Peek is used for debugging purposes.
        .map(number -> number * 2) //Transform the number to number*2
        .forEach(number -> System.out.println("Result of stream: " + number)); //Print the results.
}

In the third example, the code:

  • Prints the debugging texts with peek().
  • Filters the odd numbers.
  • Then, sorts all elements with Reverse Order which is Descending Order.
  • With limit(4), when the 4th odd number is filtered which is “1”, it does not continue to do operations for other elements.
  • Prints the debugging texts with peek(),
  • Transform the elements to (elements*2).
  • Prints the results with forEach().

sort elements by using java streams

Java Streams Distinct Example

Java Stream distinct() method removes the repeated elements in the stream. I will share an example to show how it works.

public class StreamDistinct {

    List<Integer> numbers = new ArrayList<>();

    @BeforeEach
    public void setup() {
       Collections.addAll(numbers, 1, 2, 3, 4, 4, 4, 5, 5, 5, 5);
    }

    @AfterEach
    public void tearDown() {
        numbers.clear();
    }

    @Test
    public void streamDistinctTest() {
        System.out.println("Stream operations are starting!");

        numbers.stream()
            .distinct()
            .forEach(number -> System.out.println("Result of stream: " + number)); //Print the results.

        System.out.println("Stream operations finished!");
    }
}

Output

In the example, the integer list contains 10 elements and as you have seen numbers 4 and 5 are repeating. In the stream pipeline, we used the distinct method to removed the repeats for numbers 4 and 5.

java stream distinct example

GitHub Project

https://github.com/swtestacademy/java-functional/tree/main/src/test/java/functional/stream/intermediateoperations

In this article, we covered the most commonly used Java Streams intermediate operations. In the next articles, we will learn comparator, terminal operations, and more.

Thanks for reading,
Onur Baskirt

1 thought on “Java Streams Intermediate Operations with Examples”

  1. Very nice articles makes it easier and understandable. Formatting is also good making it concise. Good work. Thanks

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.