Reduction Operations on streams
satya - 8/12/2018, 2:06:27 PM
Reduction operations are documented here
satya - 8/12/2018, 2:33:06 PM
This streams package API covers
//Various streams
BaseStream
IntStream
LongStream
DoubleStream
Stream<T> //any type of stream
//Utilities
StreamSupport
//Documentation
Theory and use of Streams
Pipelines
Parallelism
Non-interference
Stateless behavior
side effects
Ordering
Reduction
Mutable reduction
Reduction, concurrency, and Ordering
Associatiity
Low-level Stream Construction
satya - 8/12/2018, 4:32:11 PM
Consider a class designed to collect names of people
/*
* To demonstrate custom collector
* See Test5
*/
public class NameCollector
{
public List<String> names = new ArrayList<>();
//The accept method
public void addName(Person p)
{
names.add(p.name);
}
public void combine(NameCollector other)
{
names.addAll(other.names);
}
}
satya - 8/12/2018, 4:32:40 PM
You can use it this way to collect names
/*
* To demonstrate a custom collector
* See NameCollector class that enables this functionality
*
* Approach used by collect
*
* 1. Createa new one with the Supplier interface:
* NameCollector::new
*
* 2. This is also what is returned and must match
* NameCollector peopleNames
*
* 3. Repeatedly call NameCollector::addName(Person)
*
* 4. If parallel, allow
* NameCollector::combine(NameCollector another)
* to enhance the original NameCollector
*
* 5. Finally return NameCollector which
* is instantiated in step 1
*
*/
private void test5()
{
Collection<Person> people =
Person.createRoster();
NameCollector peopleNames =
people.stream()
.collect(NameCollector::new
,NameCollector::addName
,NameCollector::combine);
System.out.println("Test5: peoples names:" + peopleNames.names);
}
satya - 8/12/2018, 4:50:09 PM
Same thing with generic Collector
private void test6()
{
Collection<Person> people =
Person.createRoster();
List<String> peopleNames =
people.stream()
.map(p -> p.name) //just get a stream of names
.collect(Collectors.toList()); //stick them in a list
System.out.println("Test6: peoples names:" + peopleNames);
}
satya - 8/12/2018, 4:54:09 PM
From there
// Accumulate names into a List
List<String> list = people.stream().map(Person::getName)
.collect(Collectors.toList());
// Accumulate names into a TreeSet
Set<String> set = people.stream().map(Person::getName)
.collect(Collectors.toCollection(TreeSet::new));
// Convert elements to strings and concatenate them,
//separated by commas
String joined = things.stream()
.map(Object::toString)
.collect(Collectors.joining(", "));
// Compute sum of salaries of employee
int total = employees.stream()
.collect(Collectors.summingInt(Employee::getSalary)));
// Group employees by department
Map<Department, List<Employee>> byDept
= employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
// Compute sum of salaries by department
Map<Department, Integer> totalByDept
= employees.stream()
.collect(Collectors.groupingBy
(Employee::getDepartment,
Collectors.summingInt(Employee::getSalary)));
// Partition students into passing and failing
Map<Boolean, List<Student>> passingFailing =
students.stream()
.collect(Collectors
.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
satya - 9/11/2018, 8:52:23 PM
Collector interface itself is documented here
satya - 9/11/2018, 8:57:50 PM
Consider this code
double average = roster
.stream()
.filter(p -> p.getGender() == Person.Sex.MALE)
.mapToInt(Person::getAge)
.average()
.getAsDouble();
satya - 9/11/2018, 8:59:03 PM
Defining a reduce operation
JDK contains many terminal operations (such as average, sum, min, max, and count) that return one value by combining the contents of a stream. These operations are called reduction operations. The JDK also contains reduction operations that return a collection instead of a single value. Many reduction operations perform a specific task, such as finding the average of values or grouping elements into categories. However, the JDK provides you with the general-purpose reduction operations reduce and collect