Tim*_*sen 4 java lambda java-stream collectors
关于使用流进行简化的Oracle跟踪提供了一个示例,说明如何将一组人转换为包含基于性别的平均年龄的地图.它使用以下Person类和代码:
public class Person {
private int age;
public enum Sex {
MALE,
FEMALE
}
private Sex sex;
public Person (int age, Sex sex) {
this.age = age;
this.sex = sex;
}
public int getAge() { return this.age; }
public Sex getSex() { return this.sex; }
}
Map<Person.Sex, Double> averageAgeByGender = roster
.stream()
.collect(
Collectors.groupingBy(
Person::getSex,
Collectors.averagingInt(Person::getAge)));
Run Code Online (Sandbox Code Playgroud)
上面的流代码工作得很好,但我想看看如何在使用收集器的自定义实现时执行相同的操作.我无法在Stack Overflow或网络上找到如何执行此操作的完整示例.至于为什么我们可能想要这样做,作为一个例子,也许我们想要计算某种涉及年龄的加权平均值.在这种情况下,默认行为是Collectors.averagingInt不够的.
只是Collector.of(Supplier, BiConsumer, BinaryOperator, [Function,] Characteristics...)用于那些情况:
Collector.of(() -> new double[2],
(a, t) -> { a[0] += t.getAge(); a[1]++; },
(a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
a -> (a[1] == 0) ? 0.0 : a[0] / a[1])
)
Run Code Online (Sandbox Code Playgroud)
虽然定义一个可能更具可读性PersonAverager:
class PersonAverager {
double sum = 0;
int count = 0;
void accept(Person p) {
sum += p.getAge();
count++;
}
PersonAverager combine(PersonAverager other) {
sum += other.sum;
count += other.count;
return this;
}
double average() {
return count == 0 ? 0 : sum / count;
}
}
Run Code Online (Sandbox Code Playgroud)
并将其用作:
Collector.of(PersonAverager::new,
PersonAverager::accept,
PersonAverager::combine,
PersonAverager::average)
Run Code Online (Sandbox Code Playgroud)