reduce()操作組合流中的所有元素以產(chǎn)生單個(gè)值。
reduce操作采用兩個(gè)稱為種子(初始值)和累加器的參數(shù)。
累加器是一個(gè)函數(shù)。如果流是空的,種子是結(jié)果。
種子和一個(gè)元素被傳遞給累加器,它返回部分結(jié)果。然后將部分結(jié)果和下一個(gè)元素傳遞給累加器函數(shù)。
這重復(fù),直到所有元素被傳遞到累加器。累加器返回的最后一個(gè)值是reduce操作的結(jié)果。
流相關(guān)接口包含兩個(gè)稱為reduce()和collect()的方法來執(zhí)行通用reduce操作。
諸如sum(),max(),min(),count()等方法在IntStream,LongStream和DoubleStream接口中定義。
count()方法適用于所有類型的流。
Stream<T> 接口包含一個(gè)reduce()方法來執(zhí)行reduce操作。該方法有三個(gè)重載版本:
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)
第一個(gè)版本的reduce()方法使用一個(gè)標(biāo)識和一個(gè)累加器作為參數(shù),并將流reduce為同一類型的單個(gè)值。
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); } }
上面的代碼生成以下結(jié)果。
計(jì)算所有員工的收入總和。
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; } }
上面的代碼生成以下結(jié)果。
第二個(gè)版本的reduce方法如下所示允許我們執(zhí)行一個(gè)map操作,隨后執(zhí)行reduce操作。
<U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)
第三個(gè)參數(shù)用于組合部分結(jié)果當(dāng)并行執(zhí)行縮減操作時(shí)。
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; } }
上面的代碼生成以下結(jié)果。
Java Streams API支持并行映射縮減操作。
當(dāng)使用以下reduce方法時(shí),每個(gè)線程使用累加器累加部分結(jié)果。最后,組合器用于組合來自所有線程的部分結(jié)果以獲得結(jié)果。
<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; } }
上面的代碼生成以下結(jié)果。
第三個(gè)版本的reduce()如下列方法用于執(zhí)行沒有默認(rèn)值的縮減操作。
reduce(BinaryOperator<T> accumulator)
如果流是空的,我們不能使用默認(rèn)值為0。
Optional<T>
用于包裝結(jié)果或不存在結(jié)果。
以下代碼顯示如何計(jì)算流中的整數(shù)的最大值:
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."); } } }
上面的代碼生成以下結(jié)果。
以下代碼打印員工列表中最高收入者的詳細(xì)信息。
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; } }
上面的代碼生成以下結(jié)果。
更多建議: