When using Java streams, most of the time you will have a Collection as a source for the stream but you can also do the opposite i.e. obtain a Collection from a Stream. To do that you can use collect()
method in the Java Stream API. Here note that collect() method performs a mutable reduction operation on the elements of this stream which returns a mutable result container. This mutable result container can be a Collection class like ArrayList, HashSet or a StringBuilder etc.
collect() method in Java Stream
collect() method is a terminal operation and there are two overloaded collect() methods.
1- <R,A> R collect(Collector<? super T,A,R> collector)- Performs a mutable reduction operation on the elements of this stream using a Collector.
In the method type parameters are as-
T- The type of input elements to the reduction operation
A - the intermediate accumulation type of the Collector
R - the type of the result
2-<R> R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)- Performs a mutable reduction operation on the elements of this stream.
Parameters of the method are as follows-
R- the type of the mutable result container
supplier- a function that creates a new mutable result container. It is an instance of Supplier functional interface.
accumulator- an associative, non-interfering, stateless function that must fold an element into a result container. It is an instance of BiConsumer functional interface.
combiner- an associative, non-interfering, stateless function that accepts two partial result containers and merges them, which must be compatible with the accumulator function. It is an instance of BiConsumer functional interface.
Collectors class in Java Stream
In the first collect() method you can see that argument is of type Collector which is an interface in java.util.stream package and defines many methods.
Rather than implementing those methods yourself you can use Collectors class which is an implementation of Collector and provides many utility reduction methods such as accumulating elements into collections, summarizing elements according to various criteria, etc.
Java Collectors example
In this section we’ll see some examples of using predefined Collectors along with collect() method.
Most of the examples use objects of Employee class which has fields name, dept, salary.
public class Employee { private String name; private String dept; private int salary; Employee(String name, String dept, int salary){ this.name = name; this.dept = dept; this.salary = salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } public String getDept() { return dept; } public void setDept(String dept) { this.dept = dept; } }1. Collecting into a list – Collectors.toList() Collecting all the employee names to a List.
List<Employee> employeeList = new ArrayList<>(); employeeList.add(new Employee("Jack", "Finance", 5500)); employeeList.add(new Employee("Lisa", "Finance", 5600)); employeeList.add(new Employee("Scott", "Finance", 7000)); employeeList.add(new Employee("Nikita", "IT", 4500)); employeeList.add(new Employee("Tony", "IT", 8000)); List<String> names = employeeList.stream() .map(e -> e.getName()) .collect(Collectors.toList()); names.forEach(System.out::println);Output
Jack Lisa Scott Nikita Tony
2. Collecting into a Set – Collectors.toSet()
Set<String> names = employeeList.stream() .map(Employee::getName) .collect(Collectors.toSet()); names.forEach(System.out::println);Output
Tony Nikita Jack Lisa Scott
3. Collecting into a TreeSet – Collectors.toCollection()
Collecting all the employee names into a TreeSet to get names in order.Set<String> names = employeeList.stream() .map(Employee::getName) .collect(Collectors.toCollection(TreeSet::new)); names.forEach(System.out::println);Output
Jack Lisa Nikita Scott Tony
4. Collecting into a Map – Collectors.toMap()
To accumulate elements into a Map using toMap() method you need to provide two functions-
keyMapper- This function is used to get keys by applying function to the input elements.
valueMapper- This function is used to get values by applying function to the input elements.
Map<String, Integer> names = employeeList.stream() .collect(Collectors.toMap(Employee::getName, Employee::getSalary)); names.entrySet().forEach(es->{System.out.println("Key- " + es.getKey() + " Value- " + es.getValue());});Output
Key- Tony Value- 8000 Key- Nikita Value- 4500 Key- Jack Value- 5500 Key- Lisa Value- 5600 Key- Scott Value- 7000
5. Convert elements to strings and concatenate them- Collectors.joining
If you want to display employee names as a comma separated string.
String names = employeeList.stream() .map(Employee::getName) .collect(Collectors.joining(", ")); System.out.println(names);Output
Jack, Lisa, Scott, Nikita, Tony
6. Computing sum- Collectors.summingInt()
Sum of salaries paid to employees.
int totalSalary = employeeList.stream() .collect(Collectors.summingInt(Employee::getSalary)); System.out.println("Total salary paid to employees per month- " + totalSalary);Output
Total salary paid to employees per month- 30600
7. Grouping by a field- Collectors.groupingBy()
If you want to group the employees by department, return value is a Map.
Map<String, List<Employee>> names = employeeList.stream() .collect(Collectors.groupingBy(Employee::getDept)); names.entrySet().forEach(es->{System.out.println("Key- " + es.getKey()); System.out.println("Values"); es.getValue().forEach(e->System.out.println(e.getName()));});Output
Key- Finance Values Jack Lisa Scott Key- IT Values Nikita Tony8. Collectors.partitioningBy
Returns a Collector which partitions the input elements according to a Predicate, and organizes them into a Map<Boolean, List<T>>. The returned Map always contains mappings for both false and true keys. For true key those elements matching the given predicate are mapped and the elements not matching the given predicate are mapped under false key.
To partition employees into groups having salary >= 7000 and less than it.
Map<Boolean, List<Employee>> names = employeeList.stream() .collect(Collectors.partitioningBy(e -> e.getSalary() >= 7000));Output
Key- false Values Jack Lisa Nikita Key- true Values Scott Tony9. Collectors.teeing
Returns a Collector that is a composite of two downstream collectors. Every element passed to the resulting collector is processed by both downstream collectors, then their results are merged using the specified merge function into the final result. This method is added in JDK 12.
Getting count and sum of elements in a List using Collectors.teeing function.
List<Integer> listOfNumbers = Arrays.asList(11, 10, 9, 99, 98); List<String> list = listOfNumbers.stream().collect(Collectors.teeing(Collectors.counting(), Collectors.summingInt(n->Integer.valueOf(n.toString())), (a, s)->{List<String> l = new ArrayList<>(); l.add(a.toString()); l.add(s.toString()); return l;})); list.forEach(System.out::println);Output
5 227
10. Summary statistics methods in Collectors class
There are three methods summarizingInt, summarizingLong and summarizingDouble that returns summary statistics for the resulting values.
To get summary statistics about the salary of employees.
IntSummaryStatistics stats = employeeList.stream().collect(Collectors.summarizingInt(Employee::getSalary)); System.out.println("Sum of salaries - " + stats.getSum()); System.out.println("Average of salaries " + stats.getAverage()); System.out.println("Max salary " + stats.getMax()); System.out.println("Min salary " + stats.getMin());Output
Sum of salaries - 30600 Average of salaries 6120.0 Max salary 8000 Min salary 4500
Using collect method with Combiner
This form of collect method requires three functions: a supplier function to construct new instances of the result container, an accumulator function to incorporate an input element into a result container, and a combining function to merge the contents of one result container into another.
For example collect the Integer representations of the elements in a stream into an ArrayList.
List<Integer> numbers = Stream.of(1, 2, 3, 4, 5).collect(ArrayList::new, ArrayList::add, ArrayList::addAll); numbers.forEach(System.out::println);Output
1 2 3 4 5
Getting all the employee names as a concatenated string where values are separated by comma.
String concat = employeeList.stream().map(Employee::getName).collect( () -> new StringJoiner(",", "", ""), StringJoiner::add, StringJoiner::merge).toString(); System.out.println("Employee Names- " + concat);Output
Employee Names- Jack,Lisa,Scott,Nikita,TonyReference: https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/stream/Collectors.html
That's all for the topic Java Stream - Collectors Class And collect() Method. If something is missing or you have something to share about the topic please write a comment.
You may also like
- Java Stream Collectors.joining() Method With Examples
- Java Primitive Type Streams With Examples
- Runnable Vs Callable in Java
- Java Exception Handling Best Practices
- while Loop in Java With Examples
- How to Copy a Directory in Java
- Input from User in Python – input() function
- spring-boot-starter-parent in Spring Boot
No comments:
Post a Comment