Java 8 Stream Operations with Examples

Java 8 Stream Operations with Examples | We will see the different methods of Java 8 Stream which are very commonly used in the code. Also see:- Java 8 Interview Questions

  1. filter

Fetch all numbers from a list that are greater than 5.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> result = numbers.stream()
                              .filter(n -> n > 5)
                              .collect(Collectors.toList());
System.out.println(result); // [6, 7, 8, 9, 10]
  1. map

Transform a list of strings into a list of their uppercase versions.

List<String> words = Arrays.asList("apple", "banana", "cherry");
List<String> result = words.stream()
                           .map(str -> str.toUpperCase())
                           .collect(Collectors.toList());
System.out.println(result); // [APPLE, BANANA, CHERRY]
  1. flatMap

Given a list of lists of subjects, flatten them into a single list of subjects.

List<List<String>> listOfLists = Arrays.asList(
    Arrays.asList("English", "Science"),
    Arrays.asList("Math", "Computer Science")
);
List<String> subjects = listOfLists.stream()
                                   .flatMap(subject -> subject.stream())
                                   .collect(Collectors.toList());
System.out.println(subjects); // [English, Science, Math, Computer Science]
  1. distinct

Remove duplicates from a list of integers.

List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 4);
List<Integer> results = numbers.stream()
                               .distinct()
                               .collect(Collectors.toList());
System.out.println(results); // [1, 2, 3, 4]
  1. sorted

Sort a list of names in reverse alphabetical order.

List<String> names = Arrays.asList("John", "Jane", "Alice", "Bob");
List<String> results = names.stream()
                            .sorted(Comparator.reverseOrder())
                            .collect(Collectors.toList());
System.out.println(results); // [John, Jane, Bob, Alice]

Instead of sorted(Comparator.reverseOrder()) we can also use sorted(Collections.reverseOrder()) or sorted((a, b) -> b.compareTo(a)).

  1. peek

Print each element in a list while converting them to uppercase.

List<String> names = Arrays.asList("John", "Jane", "Alice", "Bob");
List<String> results = names.stream()
                            .map(name -> name.toUpperCase())
                            .peek(System.out::println)
                            .collect(Collectors.toList());
System.out.println(results); 

Output:-

The peek method in Java Streams is primarily used for debugging purposes. It allows to perform an intermediate operation on each element of the stream without modifying the stream itself.

  1. limit

Find the first 3 smallest numbers in a given list of integers.

List<Integer> numbers = Arrays.asList(10, 2, 13, 40, 5, 26, 77, 58, 91, 11);
List<Integer> results = numbers.stream()
                            .sorted()
                            **.limit(3)**
                            .collect(Collectors.toList());
System.out.println(results); // [2, 5, 10]
  1. skip

Fetch all the elements except the first 3 smallest numbers from a list of integers.

List<Integer> numbers = Arrays.asList(10, 2, 13, 40, 5, 26, 77, 58, 91, 11);
List<Integer> results = numbers.stream()
                               .sorted()
                               .skip(3)
                               .collect(Collectors.toList());
System.out.println(results); // [11, 13, 26, 40, 58, 77, 91]
  1. forEach

Print each element of a list of strings with the prefix “Item: “.

List<String> words = Arrays.asList("apple", "banana", "cherry");
words.stream()
     .forEach(word -> System.out.println("Item: " + word));
// Item: apple, Item: banana, Item: cherry
  1. collect

Collect a list of integers into a Set.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 4, 5);
Set<Integer> result = numbers.stream()
                             .collect(Collectors.toSet());
// result: [1, 2, 3, 4, 5]
  1. reduce

The reduce method in Java Streams is used to perform a reduction on the elements of a stream, combining them into a single result. It applies a binary operation (a function that takes two arguments and returns a single result) to the elements of the stream, repeatedly, until all elements have been processed and a single value remains.

Compute the product of all numbers in a list.

List<Integer> numbers = Arrays.asList(10, 2, 13, 40);
Integer results = numbers.stream()
                         .reduce((a,b) -> a*b)
                         .get();
System.out.println(results); // 10400

Compute the sum of all numbers in a list.

List<Integer> numbers = Arrays.asList(10, 2, 13, 40);
Integer results = numbers.stream()
                         .reduce((a,b) -> a+b)
                         .get();
System.out.println(results); // 65
  1. allMatch

The allMatch method in Java Streams is used to check if all elements in the stream satisfy a given predicate. It returns true if every element in the stream matches the predicate, and false otherwise.

Check if all numbers in the list are positive.

List<Integer> numbers = Arrays.asList(10, 2, 13, 40);
Boolean results = numbers.stream().allMatch(a -> a > 0);
System.out.println(results); // true
  1. anyMatch

The anyMatch method checks whether at least one element in the stream matches a given predicate. It returns true as soon as it finds an element that satisfies the predicate and stops further processing. If no elements match, it returns false.

Check if any number in the list is greater than 10.

List<Integer> numbers = Arrays.asList(5, 8, 12, 3);
boolean result = numbers.stream()
                        .anyMatch(n -> n > 10);
System.out.println(result); // true
  1. noneMatch

The noneMatch method in Java Streams is used to check if no elements in the stream match a given predicate. It returns true if none of the elements satisfy the predicate and false if at least one element does.

Check if no elements in the list are negative.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean result = numbers.stream()
                        .noneMatch(n -> n < 0);
System.out.println(result); // true
  1. findFirst

The findFirst is used to retrieve the first element in a stream that matches a given condition or simply the first element in the stream if no filtering is applied. It returns the first element wrapped in an Optional, which is a container object that may or may not contain a non-null value.

Find the first element in a list that starts with the letter ‘b’.

List<String> words = Arrays.asList("apple", "banana", "cherry", "blackberry");
String result = words.stream()
                     .filter(s -> s.startsWith("b"))
                     .findFirst().get();
System.out.println(result); // banana
  1. findAny

It retrieves any element from the stream that matches a given condition, or simply any element from the stream if no filtering is applied. It returns the element wrapped in an Optional, which may or may not contain a value.

Find any element in a list that starts with the letter ‘b’.

List<String> words = Arrays.asList("apple", "banana", "cherry", "blackberry");
String result = words.stream().filter(s -> s.startsWith("b")).findAny().get();
System.out.println(result); 
  1. max and min

They are used to find the maximum and minimum elements in a stream, respectively, based on a given comparator or natural ordering. These methods return an Optional because the stream might be empty. Both methods return an Optional<T> to handle the case where the stream might be empty.

Find the maximum and minimum values from a list of integers.

List<Integer> numbers = Arrays.asList(5, 1, 8, 3, 9);
Integer max = numbers.stream().max(Integer::compareTo).get();
Integer min = numbers.stream().min(Integer::compareTo).get();
System.out.println(max + " " + min); // 9 1

Or, the same can be done as:-

Integer max = numbers1.stream().max((a, b) -> a.compareTo(b)).get();
Integer min = numbers1.stream().min((a, b) -> a.compareTo(b)).get();
  1. toArray

Convert a list of Strings into an array.

List<String> words = Arrays.asList("apple", "banana", "cherry", "blackberry");

// String[] result = words.toArray(new String[0]);
String[] result = words.toArray(String[]::new);

System.out.println(Arrays.toString(result));
// [apple, banana, cherry, blackberry]
  1. joining

It is used to concatenate the elements of a stream into a single String. It’s part of the Collectors utility class and provides a convenient way to aggregate elements into a string format with optional delimiters, prefixes, and suffixes. Method:- joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)

Concatenate all strings in a list into a single string separated by commas.

List<String> words = Arrays.asList("apple", "banana", "cherry", "blackberry");
String result = words.stream().collect(Collectors.joining(", "));
System.out.println(result);
// apple, banana, cherry, blackberry
String concatedString1 = words.stream().collect(Collectors.joining(", ", "[", "]"));
System.out.println(concatedString1); // [apple, banana, cherry, blackberry]
  1. count

Count the number of strings in a list.

List<String> words = Arrays.asList("apple", "banana", "cherry", "blackberry");
long count = words.stream().count();
System.out.println(count); // 4

Count the number of strings starting with “b” in a given list.

List<String> words = Arrays.asList("apple", "banana", "cherry", "blackberry");
long count = words.stream().filter(s -> s.startsWith("b")).count();
System.out.println(count); // 2
  1. counting

The counting method in Java Streams is a collector that counts the number of elements in the stream. It’s often used in conjunction with other collectors for aggregation. It is very similar to the previous count() method.

Return Type: A Collector<T, ?, Long> that counts the elements in the stream.

Count the number of strings in a list.

List<String> words = Arrays.asList("apple", "banana", "cherry", "blackberry");
long count = words.stream()
    .filter(s -> s.startsWith("b")).collect(Collectors.counting());
System.out.println(count); // 2

Complex Java 8 Stream Operations

  1. groupingBy

It groups elements of the stream by a specified classifier function. It is a powerful feature provided by the Collectors utility class and is commonly used for aggregating and categorizing data into a Map where the keys are the result of applying the classifier function and the values are lists of items corresponding to each key.

Group a list of employee by their city.

public class Employee {
    private String name;
    private String city;
    // setter, getter, constructor, toString
}
List<Employee> employees = Arrays.asList(
                new Employee("John", "New York"),
                new Employee("Jane", "London"),
                new Employee("Jack", "New York")
            );
Map<String, List<Employee>> employeeByCity = employees.stream()
                .collect(Collectors.groupingBy(Employee::getCity));
System.out.println(employeeByCity);
// or
employees.stream().collect(Collectors.groupingBy(e -> e.getCity()));

Output:-

{
  NewYork=[
    Employee(name=John, city=NewYork),
    Employee(name=Jack, city=NewYork)
  ],
  London=[
    Employee(name=Jane, city=London)
  ]
}
  1. partitioningBy

The partitioningBy method in Java Streams is used to partition the elements of a stream into two groups based on a specified predicate. It returns Map where the keys are Boolean, and the values are lists of elements that satisfy (or do not satisfy) the predicate.

Return Type: A Map<Boolean, List<T>> where:

  • Key true contains elements that satisfy the predicate.
  • Key false contains elements that do not satisfy the predicate.

Partition a list of integers into even and odd numbers.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
Map<Boolean, List<Integer>> result = numbers.stream()
      .collect(Collectors.partitioningBy(n -> n % 2 == 0));
System.out.println(result);
// {false=[1, 3, 5], true=[2, 4, 6]}
  • Use Case: Categorizing employees based on their performance ratings.
  • Predicate: Employees with performance ratings above a certain threshold (e.g., 4.0).
  • True group: High-performing employees.
  • False group: Regular-performing employees.
Map<Boolean, List<Employee>> employeePartition = employeeList.stream()
    .collect(Collectors.partitioningBy(employee -> employee.getPerformanceRating() > 4.0));

This can be useful for HR departments to identify high-performing employees for rewards, promotions, or additional training programs.

  1. summarizingInt

The summarizingInt method in Java Streams is a collector that generates summary statistics for the elements of a stream, including count, sum, minimum, average, and maximum.

Return Type: An IntSummaryStatistics object containing the summary statistics.

Generate summary statistics (count, sum, min, average, max) for a list of integers.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// IntSummaryStatistics stats = numbers.stream()
//         .mapToInt(x -> x).summaryStatistics();
IntSummaryStatistics stats = numbers.stream()
           .collect(Collectors.summarizingInt(Integer::intValue));

System.out.println(stats);
// IntSummaryStatistics{count=5, sum=15, min=1, average=3.000000, max=5}

System.out.println(stats.getAverage() + " " + stats.getSum()); // 3.0 15
  1. mapping

The mapping method in Java Streams is used to apply a mapping function to the elements of a stream and then collect the results using another collector.

Return Type: A Collector that applies a mapping function and collects the results.

Extract and collect the lengths of all strings in a list.

List<String> words = Arrays.asList("apple", "banana", "cherry");
List<Integer> lengths = words.stream()
   .collect(Collectors.mapping(String::length, Collectors.toList()));
System.out.println(lengths); // [5, 6, 6]

Use case:- Extract customer email addresses from a list of orders for sending marketing or order status updates.

List customerEmails = orderList.stream()
 .collect(Collectors.mapping(order -> order.getCustomer().getEmail(), Collectors.toList()));
  1. joining with delimiter, prefix, and suffix

The joining method in Java Streams concatenates the elements of a stream into a single String, with optional delimiters, prefixes, and suffixes.

Return Type: A Collector that concatenates the elements of a stream into a single String.

Concatenate all strings in a list into a single string with commas, a prefix, and a suffix.

List<String> words = Arrays.asList("apple", "banana", "cherry");
String result = words.stream()
                     .collect(Collectors.joining(", ", "[", "]"));
System.out.println(result); // [apple, banana, cherry]
  1. groupingBy with downstream collector

The groupingBy method in Java Streams groups the elements of the stream by a classifier function and can also apply a downstream collector to the results.

Return Type: A Map<K, D> where K is the type of the classifier, and D is the result of the downstream collector.

Group a list of strings by their length and count the number of strings in each group.

List<String> words = Arrays.asList("apple", "banana", "cherry", "blueberry");
Map<Integer, Long> groupedByLength = words.stream()
       .collect(Collectors.groupingBy(String::length, Collectors.counting()));
System.out.println(groupedByLength); // {5=1, 6=2, 9=1}

Use case: We can use groupingBy to group orders by customer and then count how many orders each customer has placed using counting as a downstream collector.

Map<Customer, Long> ordersByCustomer = orderList.stream()
 .collect(Collectors.groupingBy(Order::getCustomer, Collectors.counting()));
  1. filtering

The filtering method is used to filter elements of a stream and then collect the results using another collector.

Return Type: A Collector that filters elements and collects the results.

Filter and collect only the even numbers from a list of integers.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> evens = numbers.stream()
        .collect(Collectors.filtering(n -> n % 2 == 0, Collectors.toList()));
System.out.println(evens); // [2, 4, 6, 8, 10]
  1. collectingAndThen

The collectingAndThen method in Java Streams is a collector that first applies a collection operation and then applies another function to the result.

Return Type: A Collector<T, A, R> that first collects elements and then transforms the result.

Convert a stream of strings into a set and then get its size.

List<String> words = Arrays.asList("apple", "banana", "cherry", "banana");
int count = words.stream()
   .collect(Collectors.collectingAndThen(Collectors.toSet(), Set::size));
System.out.println(count); // 3
  1. mapping with downstream collector

The mapping method is used to apply a mapping function to elements in a stream and then collect the results using another collector.

Return Type: A Collector<T, A, R> that applies a mapping function and collects the results.

Collect the lengths of all strings in a list and sum them.

List<String> words = Arrays.asList("apple", "banana", "cherry");
int totalLength = words.stream()
    .collect(Collectors.mapping(String::length, 
             Collectors.summingInt(Integer::intValue)));
System.out.println(totalLength); // 17
  1. toMap

The toMap method in Java Streams converts the elements of a stream into a Map using a key and a value mapping function.

Return Type: A Map<K, V> where K is the key type and V is the value type.

Convert a list of strings into a map where the key is the string and the value is its length.

List<String> words = Arrays.asList("apple", "banana", "cherry");
Map<String, Integer> map = words.stream()
     .collect(Collectors.toMap(Function.identity(), String::length));
System.out.println(map); // {banana=6, apple=5, cherry=6}

Use case:- create a map where each order ID is associated with its total amount.

Map<Long, Integer> orderAmountMap = orderList.stream()
   .collect(Collectors.toMap(Order::getId, Order::getTotalAmount));
  1. toConcurrentMap

The toConcurrentMap method in Java Streams is similar to toMap, but it produces a ConcurrentMap for thread-safe operations. When multiple threads might access or modify the map simultaneously, This collector ensures that the resulting map is thread-safe and can be safely used in concurrent environments.

Return Type: A ConcurrentMap<K, V> where K is the key type and V is the value type.

Convert a list of strings into a concurrent map where the key is the string and the value is its length.

List<String> words = Arrays.asList("apple", "banana", "cherry");
ConcurrentMap<String, Integer> map = words.stream()
   .collect(Collectors.toConcurrentMap(Function.identity(), String::length));
System.out.println(map); // {banana=6, apple=5, cherry=6}
  1. reducing

The reducing method in Java Streams is used to perform a reduction on the elements of the stream using an associative accumulation function.

It takes 2 arguments-

  • Identity Value (optional): A starting value that serves as the initial result and is used as the default when the stream is empty.
  • Binary Operator: A function that takes two arguments and returns a combined result.
    Return Type: An Optional<T> if no identity is provided or T if an identity is provided.

Find the sum of a list of integers.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
        .collect(Collectors.reducing(0, Integer::sum));
System.out.println(sum); // 15
collect(Collectors.reducing(0, (a, b) -> a + b));
  1. flatMapping

The flatMapping method is used to flatten a stream of collections and then apply a collector to the flattened elements.

Return Type: A Collector that applies a flat-mapping function and collects the results.

Flatten a list of lists of integers and collect the result as a single list.

List<List<Integer>> listOfLists = Arrays.asList(
    Arrays.asList(1, 2, 3),
    Arrays.asList(4, 5, 6),
    Arrays.asList(7, 8, 9)
);
List<Integer> flattenedList = listOfLists.stream()
         .collect(Collectors.flatMapping(Collection::stream, Collectors.toList()));
System.out.println(flattenedList); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
  1. groupingByConcurrent

The groupingByConcurrent method in Java Streams is similar to groupingBy, but it returns a ConcurrentMap for thread-safe operations.

Return Type: A ConcurrentMap<K, List<T>> where K is the type of the classifier.

Group a list of strings by their length in a thread-safe manner.

List<String> words = Arrays.asList("apple", "banana", "cherry", "date");
ConcurrentMap<Integer, List<String>> groupedByLength = words.stream()
           .collect(Collectors.groupingByConcurrent(String::length));
System.out.println(groupedByLength); 
// {4=[date], 5=[apple], 6=[banana, cherry]}
  1. teeing

The teeing method in Java Streams allows combining two collectors into one, where the results of the two collectors are then combined into a final result.

Return Type: A Collector<T, ?, R> that combines the results of two collectors.

Compute both the sum and the count of a list of integers and return the result as a pair.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Map<String, Integer> result = numbers.stream()
            .collect(
                 Collectors.teeing(
                    Collectors.summingInt(Integer::intValue), 
                    Collectors.counting(),
                    (sum, count) -> Map.of("sum", sum, "count", count.intValue())
                 )
             );
System.out.println(result); // {sum=15, count=5}

If you enjoyed this post, share it with your friends. Do you want to share more information about the topic discussed above or do you find anything incorrect? Let us know in the comments. Thank you!

Leave a Comment

Your email address will not be published. Required fields are marked *