Java 流组合
Java流 - Java流组合
reduce()操作组合流中的所有元素以产生单个值。
reduce操作采用两个称为种子(初始值)和累加器的参数。
累加器是一个函数。如果流是空的,种子是结果。
种子和一个元素被传递给累加器,它返回部分结果。然后将部分结果和下一个元素传递给累加器函数。
这重复,直到所有元素被传递到累加器。累加器返回的最后一个值是reduce操作的结果。
流相关接口包含两个称为reduce()和collect()的方法来执行通用reduce操作。
诸如sum(),max(),min(),count()等方法在IntStream,LongStream和DoubleStream接口中定义。
count()方法适用于所有类型的流。
Stream<T> 接口包含一个reduce()方法来执行reduce操作。该方法有三个重载版本:
T reduce(T identity, BinaryOperator<T> accumulator) <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner) Optional<T> reduce(BinaryOperator<T> accumulator)
第一个版本的reduce()方法使用一个标识和一个累加器作为参数,并将流reduce为同一类型的单个值。
import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.stream() .reduce(0, Integer::sum); System.out.println(sum); } }
上面的代码生成以下结果。
例2
计算所有员工的收入总和。
import java.time.LocalDate; import java.time.Month; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { double sum = Employee.persons() .stream() .map(Employee::getIncome) .reduce(0.0, Double::sum); System.out.println(sum); } } class Employee { public static enum Gender { MALE, FEMALE } private long id; private String name; private Gender gender; private LocalDate dob; private double income; public Employee(long id, String name, Gender gender, LocalDate dob, double income) { this.id = id; this.name = name; this.gender = gender; this.dob = dob; this.income = income; } public double getIncome() { return income; } public static List<Employee> persons() { Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971, Month.JANUARY, 1), 2343.0); Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972, Month.JULY, 21), 7100.0); Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973, Month.MAY, 29), 5455.0); Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974, Month.OCTOBER, 16), 1800.0); Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975, Month.DECEMBER, 13), 1234.0); Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976, Month.JUNE, 9), 3211.0); List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6); return persons; } }
上面的代码生成以下结果。
例3
第二个版本的reduce方法如下所示允许我们执行一个map操作,随后执行reduce操作。
<U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)
第三个参数用于组合部分结果当并行执行缩减操作时。
import java.time.LocalDate; import java.time.Month; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { double sum = Employee.persons() .stream() .reduce(0.0, (partialSum, person) -> partialSum + person.getIncome(), Double::sum); System.out.println(sum); } } class Employee { public static enum Gender { MALE, FEMALE } private long id; private String name; private Gender gender; private LocalDate dob; private double income; public Employee(long id, String name, Gender gender, LocalDate dob, double income) { this.id = id; this.name = name; this.gender = gender; this.dob = dob; this.income = income; } public double getIncome() { return income; } public void setIncome(double income) { this.income = income; } public static List<Employee> persons() { Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971, Month.JANUARY, 1), 2343.0); Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972, Month.JULY, 21), 7100.0); Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973, Month.MAY, 29), 5455.0); Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974, Month.OCTOBER, 16), 1800.0); Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975, Month.DECEMBER, 13), 1234.0); Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976, Month.JUNE, 9), 3211.0); List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6); return persons; } }
上面的代码生成以下结果。
Java流映射并行reduce
Java Streams API支持并行映射缩减操作。
当使用以下reduce方法时,每个线程使用累加器累加部分结果。最后,组合器用于组合来自所有线程的部分结果以获得结果。
<U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)
以下代码显示了如何顺序并行reduce操作工作。
import java.time.LocalDate; import java.time.Month; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { double sum = Employee .persons() .stream() .reduce( 0.0, (Double partialSum, Employee p) -> { double accumulated = partialSum + p.getIncome(); System.out.println(Thread.currentThread().getName() + " - Accumulator: partialSum = " + partialSum + ", person = " + p + ", accumulated = " + accumulated); return accumulated; }, (a, b) -> { double combined = a + b; System.out.println(Thread.currentThread().getName() + " - Combiner: a = " + a + ", b = " + b + ", combined = " + combined); return combined; }); System.out.println("--------------------------------------"); System.out.println(sum); sum = Employee .persons() .parallelStream() .reduce( 0.0, (Double partialSum, Employee p) -> { double accumulated = partialSum + p.getIncome(); System.out.println(Thread.currentThread().getName() + " - Accumulator: partialSum = " + partialSum + ", person = " + p + ", accumulated = " + accumulated); return accumulated; }, (a, b) -> { double combined = a + b; System.out.println(Thread.currentThread().getName() + " - Combiner: a = " + a + ", b = " + b + ", combined = " + combined); return combined; }); System.out.println(sum); } } class Employee { public static enum Gender { MALE, FEMALE } private long id; private String name; private Gender gender; private LocalDate dob; private double income; public Employee(long id, String name, Gender gender, LocalDate dob, double income) { this.id = id; this.name = name; this.gender = gender; this.dob = dob; this.income = income; } public double getIncome() { return income; } public static List<Employee> persons() { Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971, Month.JANUARY, 1), 2343.0); Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972, Month.JULY, 21), 7100.0); Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973, Month.MAY, 29), 5455.0); Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974, Month.OCTOBER, 16), 1800.0); Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975, Month.DECEMBER, 13), 1234.0); Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976, Month.JUNE, 9), 3211.0); List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6); return persons; } }
上面的代码生成以下结果。
流reduce没有默认值
第三个版本的reduce()如下列方法用于执行没有默认值的缩减操作。
reduce(BinaryOperator<T> accumulator)
如果流是空的,我们不能使用默认值为0。
Optional<T>
用于包装结果或不存在结果。
以下代码显示如何计算流中的整数的最大值:
import java.util.Optional; import java.util.stream.Stream; public class Main { public static void main(String[] args) { Optional<Integer> max = Stream.of(1, 2, 3, 4, 5).reduce(Integer::max); if (max.isPresent()) { System.out.println("max = " + max.get()); } else { System.out.println("max is not defined."); } max = Stream.<Integer> empty().reduce(Integer::max); if (max.isPresent()) { System.out.println("max = " + max.get()); } else { System.out.println("max is not defined."); } } }
上面的代码生成以下结果。
例5
以下代码打印员工列表中最高收入者的详细信息。
import java.time.LocalDate; import java.time.Month; import java.util.Arrays; import java.util.List; import java.util.Optional; public class Main { public static void main(String[] args) { Optional<Employee> person = Employee .persons() .stream() .reduce((p1, p2) -> p1.getIncome() > p2.getIncome() ? p1 : p2); if (person.isPresent()) { System.out.println("Highest earner: " + person.get()); } else { System.out.println("Could not get the highest earner."); } } } class Employee { public static enum Gender { MALE, FEMALE } private long id; private String name; private Gender gender; private LocalDate dob; private double income; public Employee(long id, String name, Gender gender, LocalDate dob, double income) { this.id = id; this.name = name; this.gender = gender; this.dob = dob; this.income = income; } public double getIncome() { return income; } public static List<Employee> persons() { Employee p1 = new Employee(1, "Jake", Gender.MALE, LocalDate.of(1971, Month.JANUARY, 1), 2343.0); Employee p2 = new Employee(2, "Jack", Gender.MALE, LocalDate.of(1972, Month.JULY, 21), 7100.0); Employee p3 = new Employee(3, "Jane", Gender.FEMALE, LocalDate.of(1973, Month.MAY, 29), 5455.0); Employee p4 = new Employee(4, "Jode", Gender.MALE, LocalDate.of(1974, Month.OCTOBER, 16), 1800.0); Employee p5 = new Employee(5, "Jeny", Gender.FEMALE, LocalDate.of(1975, Month.DECEMBER, 13), 1234.0); Employee p6 = new Employee(6, "Jason", Gender.MALE, LocalDate.of(1976, Month.JUNE, 9), 3211.0); List<Employee> persons = Arrays.asList(p1, p2, p3, p4, p5, p6); return persons; } @Override public String toString() { String str = String.format("(%s, %s, %s, %s, %.2f)\n", id, name, gender, dob, income); return str; } }
上面的代码生成以下结果。
更多建议: