无法弄清楚如何读取特定建筑物列表中动物的平均体重。
我编写了另一种获取每种动物的动物名称的方法,所以我知道我的持久性正在发挥作用。
动物园:
public class Zoo {
private List<Animal> animals;
private List<Building> buildings;
public Zoo() {
this.animals = new PersistencyController().giveAnimals();
this.gebouwen = new PersistencyController().giveBuildings();
}
public List<Animal> giveAnimalsByKind(String kindName) {
return animals.stream().filter(animal -> animal.getKind().getName() == kindName).sorted(Comparator.comparing(Animal::getWeight)).collect(Collectors.toList());
}
public double giveAvgWeightForAnimalsInBuilding(String buildingName) {
return animals.stream().collect(Collectors.averagingDouble(Animal::getWeight));
}
}
动物:
public class Animal implements Serializable {
private int nr;
private String name;
private double weight;
private Kind kind;
public Animal(int nr, String name, double weight, Kind kind) {
this.nr = nr;
this.name = name;
this.weight= weight;
this.kind= kind;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
}
建筑物:
public class Building{
private String naam;
private int capaciteit;
private final List<Animal> animals = new ArrayList<>();
public Building(String naam, int capaciteit) {
this.naam = naam;
this.capaciteit = capaciteit;
}
}
我想获取每个建筑物中动物的平均体重,所以我的想法是传递建筑物的名称。每个建筑物对象都存储有动物列表,我需要建筑物对象,因为它存储建筑物的名称,但是我不知道如何使用流访问它。我知道在我发布的代码中,我实际上还没有使用buildingName,但这是因为我什至无法正常获得动物的平均体重。重量存储为动物中的两倍,并且我的持久性正在发挥作用,因为我已经通过其他方式对此进行了测试。精通流的任何人都将解释如何通过构建进行过滤并获得此平均权重,这一点将不胜感激。
答案 0 :(得分:6)
如果您有使用Java9的自由,我建议您使用flatMapping
收集器来完成此工作。看起来就是这样。
Map<String, Double> avgWeightByBuildingName = buildings.stream()
.collect(Collectors.groupingBy(Building::getName,
Collectors.flatMapping(b -> b.getAnimals().stream(),
Collectors.averagingDouble(Animal::getWeight))));
不过,这是java8解决方案,与前一种解决方案相比,它看上去更加冗长。
Map<String, Double> avgWeightByBuildingName = buildings.stream()
.flatMap(b -> b.getAnimals().stream()
.map(a -> new AbstractMap.SimpleEntry<>(b.getName(), a.getWeight())))
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.averagingDouble(Map.Entry::getValue)));
或者考虑遵循此answer来编写自己的flatMapping
收藏家。看完以上答案和JDK 9源代码后,我想到了这种实现。
static <T, U, A, R> Collector<T, ?, R> flatMapping(Function<? super T,
? extends Stream<? extends U>> mapper, Collector<? super U, A, R> downstream) {
BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
return Collector.of(downstream.supplier(), (r, t) -> {
try (Stream<? extends U> result = mapper.apply(t)) {
result.sequential().forEach(u -> downstreamAccumulator.accept(r, u));
}
}, downstream.combiner(), downstream.finisher(),
downstream.characteristics().toArray(new Characteristics[0]));
}
此外,对于以下较新的Java版本,这具有简单明了的迁移策略,如下面的注释所述。