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
