Reduction Operations on streams

satya - 8/12/2018, 2:06:27 PM

Reduction operations are documented here

Reduction operations are documented here

satya - 8/12/2018, 2:27:41 PM

Java streams package API is here

Java streams package API is 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:50:54 PM

Collectors are documented here

Collectors are documented here

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

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