How do I use Collectors.counting() method?

The Collectors.counting() method is a terminal operation that returns the count of elements in the particular stream where it is used. This is part of the java.util.stream.Collectors in Java 8.

Here is a simple example of how to use Collectors.counting(). Suppose we have a list of strings, and we want to count the number of elements in it.

package org.kodejava.stream;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class CollectorsCounting {
    public static void main(String... args) {
        List<String> names = Arrays.asList("Rosa", "Bob", "Alice", "Dave", "John");

        long count = names.stream()
                .collect(Collectors.counting());

        System.out.println("Count: " + count);
    }
}

Output:

Count: 5

In this code:

  • We have a list of names.
  • We create a stream from this list using the .stream() method.
  • We count the elements of the stream using .collect(Collectors.counting()), which returns the number of elements in the stream.
  • Finally, we print the count.

When we run the program, we will get the output “Count: 5”, because there are five elements in the list.

The Collectors.counting() method is often used in conjunction with other methods like Collectors.groupingBy() to perform more complex operations like counting the number of elements in each group.

How do I use Collectors.toCollection() method?

The Collectors.toCollection() method is a static method in the java.util.stream.Collectors class of Java 8. This method is used with streams when you want to convert a list to another collection type.

Here’s a simple example of how to use the method:

package org.kodejava.stream;

import java.util.*;
import java.util.stream.Collectors;

public class CollectorsToCollection {
    public static void main(String[] args) {
        List<String> list = 
                Arrays.asList("Java", "Kotlin", "Python", "Scala", "Kotlin");

        // Convert List to TreeSet
        TreeSet<String> treeSet = list.stream()
                .collect(Collectors.toCollection(TreeSet::new));

        System.out.println(treeSet);
    }
}

Output:

[Java, Kotlin, Python, Scala]

In this code:

  • We have a List of Strings.
  • We convert this list into a TreeSet.
  • Collectors.toCollection(TreeSet::new) is the collector that collects the data from the stream into a new TreeSet.
  • The method referenced by TreeSet::new is a constructor reference that creates a new empty TreeSet.

The output of the program will be the TreeSet containing the elements of the list.

Keep in mind that a TreeSet automatically orders its elements (in this case, alphabetically since the elements are Strings) and does not allow duplicates. So, if the list had duplicate values, and you wanted to maintain them in your new collection, you would need to choose a different type of Set or use a List.

How do I use Collectors.partitioningBy() method?

Collectors.partitioningBy() is a special case of a grouping collector in Java’s Stream API. It partitions or divides the input elements into two groups, based on the result of a Predicate function. One group for which the Predicate function returns true, and the other where it returns false.

Each group is a List of elements, and the method returns a Map where the keys are Boolean values (true and false), and the values are the resulting groups.

Here’s a simple example:

package org.kodejava.stream;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class OddEvenNumberPartitioning {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        Map<Boolean, List<Integer>> isEven = numbers.stream()
                .collect(Collectors.partitioningBy(num -> num % 2 == 0));

        System.out.println("Partition of Even Numbers: " + isEven.get(true));
        System.out.println("Partition of Odd Numbers: " + isEven.get(false));
    }
}

Output:

Partition of Even Numbers: [2, 4, 6, 8, 10]
Partition of Odd Numbers: [1, 3, 5, 7, 9]

In this example, we’re partitioning a list of integers into even and odd numbers. The Predicate function num -> num % 2 == 0 returns true for even numbers and false for odd numbers.

The value that partitioningBy() method returns is a Map where the key true maps to a list of numbers for which the Predicate was true (even numbers), and the key false maps to a list of numbers for which the Predicate was false (odd numbers).

You can use partitioningBy() to easily categorize elements of a stream where the categorization criterion can be represented with a boolean value (i.e., you have a binary condition to divide your elements).

How do I use Collectors.groupingBy() method?

In Java 8, the Collectors.groupingBy() method in the Stream API is used to group elements of the stream into a `Map“ based on a categorization function.

Here’s a basic example:

package org.kodejava.stream;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class CollectorsGroupingBy {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("John", "Alice", "Rosa", "Tom", "John");

        Map<String, List<String>> groupedByName = names.stream()
                .collect(Collectors.groupingBy(Function.identity()));

        groupedByName.forEach((name, nameList) -> {
            System.out.println("Name : " + name + " Count : " + nameList.size());
        });
    }
}

Output:

Name : Tom Count : 1
Name : Alice Count : 1
Name : John Count : 2
Name : Rosa Count : 1

In this case, elements of the names list are grouped by their identity (Function.identity() returns a function that returns its input). So the resulting Map has the name as a key, and a list of names as the value. If a name appears more than once in the list, it will appear more than once in the corresponding list in the Map.

groupingBy() can also be used with more complex streams. For example, if you have a stream of Employee objects, and you want to group employees by their department, you can do it like:

package org.kodejava.stream;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class EmployeeGroupingBy {
    public static void main(String[] args) {
        // Create a list of employees
        List<Employee> employees = Arrays.asList(
                new Employee("John", 25, "Finance"),
                new Employee("Sarah", 28, "Marketing"),
                new Employee("Tom", 35, "IT"),
                new Employee("Rosa", 30, "Finance"),
                new Employee("Sam", 24, "IT"));

        // Group the employees by their department
        Map<String, List<Employee>> employeesByDepartment = employees.stream()
                .collect(Collectors.groupingBy(Employee::getDepartment));

        System.out.println(employeesByDepartment);
    }
}

class Employee {
    private final String name;
    private final int age;
    private final String department;

    public Employee(String name, int age, String department) {
        this.name = name;
        this.age = age;
        this.department = department;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getDepartment() {
        return department;
    }

    @Override
    public String toString() {
        return "name='" + name + "'";
    }
}

Output:

{Finance=[name='John', name='Rosa'], IT=[name='Tom', name='Sam'], Marketing=[name='Sarah']}

Collectors.groupingBy() is very flexible and can be used with additional parameters to provide more control over how the grouping is done, including changing the type of Map returned, modifying how the values are collected, or using a secondary groupingBy() call to create a multi-level Map.

In the above example, the groupingBy() method groups the employees by their department. The department field of the Employee object is used as the key of the Map and the value is the list of employees in that department.

The Employee::getDepartment in the groupingBy() is a method reference in Java. It’s equivalent to writing employee -> employee.getDepartment(). The :: is used to reference a method or a constructor in the Java class.

Here, Employee::getDepartment is used as a classifier function that applies to each element in the stream. So groupingBy() distributes elements of the stream into groups according to the value returned by this function.

How do I use Collectors.summarizingInt() method?

The Collectors.summarizingInt method is actually similar to the summaryStatistics we discussed in the previous example. It returns a special class (IntSummaryStatistics) which encapsulates a set of summary statistical values for a stream of integers.

Here’s an example:

package org.kodejava.stream;

import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.stream.Collectors;

public class SummarizingIntExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        IntSummaryStatistics stats = numbers.stream()
                .collect(Collectors.summarizingInt(Integer::intValue));

        System.out.println("Highest number in List : " + stats.getMax());
        System.out.println("Lowest number in List  : " + stats.getMin());
        System.out.println("Sum of all numbers     : " + stats.getSum());
        System.out.println("Average of all numbers : " + stats.getAverage());
        System.out.println("Total numbers in List  : " + stats.getCount());
    }
}

Output:

Highest number in List : 10
Lowest number in List  : 1
Sum of all numbers     : 55
Average of all numbers : 5.5
Total numbers in List  : 10

In this case, Collectors.summarizingInt is used as the collector for the stream.collect method. The Integer::intValue method reference is provided to tell it how to convert the stream elements (which are Integer objects in this case) to int values. The stream.collect method aggregates the input elements into a single summary result (the IntSummaryStatistics object).

Similar to summaryStatistics(), Collectors.summarizingInt() also provides corresponding methods for Long (Collectors.summarizingLong) and Double (Collectors.summarizingDouble) values.