【问题标题】:Trying to understand lambda and stream in Java 8试图理解 Java 8 中的 lambda 和流
【发布时间】:2014-05-04 22:48:18
【问题描述】:

我正在尝试理解 Java 8 中的 Lambda。

假设我有一个如下所示的 Person 类:

public class Person implements {
    String name;
    GenderEnum gender;
    int age;
    List<Person> children;
}

现在我想做的是找到所有有 10 岁以下孩子的女性。

Pre java 8 我会这样做:

List<Person> allPersons = somePeople();
List<Person> allFemaleWithChildren = new ArrayList<>();
for(Person p : allPersons) {
    for(Person child : p.getChildren()) {
        if(child.getAge() < 10 && p.getGender() == GenderEnum.Female) {
            allFemaleWithChildren.add(p);
        }
    }
}

现在 allFemaleWithChildren 应该有我想要的。 我一直在尝试使用流做同样的事情 我想我需要使用某种映射、过滤和归约

allPersons.stream()
//filter females
.filter(p -> p.getGender == GenderEnum.Female)
//get the children
.map(c -> c.getChildren())
//filter the ones that are less than 10 years
.filter(c -> c.getAge() < 10)
//return a list with the result
.collect(Collectors.toList())

但是这段代码无法编译。 我错过了什么。

另外,我不明白 reduce 方法可以用来做什么。

编译器说 cannot resolve method getAge()。这是因为c 显然是一个集合,而不是集合中的项目,这正是我想要的。

【问题讨论】:

  • 编译器是怎么说的? Person 类实现了什么?
  • 问题似乎出在最后一种过滤方法上。 c.getYear() 因为c 是一个集合,而不是项目的迭代器
  • @Duncan 完成。但在我看来,这无关紧要。任何清楚了解这一点的人都应该能够发现我的错误,因为我没有做正确的事情

标签: java collections lambda java-8 java-stream


【解决方案1】:

目前(一旦您修复编译错误)您将返回一个子列表。假设在您的原始代码中,您打算在找到 10 岁以下的孩子后立即中断,等效代码可能如下所示:

allPersons.stream()
    //filter females
    .filter(p -> p.getGender() == GenderEnum.Female)
    //only keep females with at least one child < 10
    .filter(f -> f.getChildren().stream()
                    .anyMatch(c -> c.getAge() < 10))
    //return a list with the result
    .collect(Collectors.toList())

事实上,正如下面评论的那样,您可以使用一些静态导入、添加辅助方法并重构原始代码以使其更具可读性:

allPersons.stream()
    .filter(this::female)
    .filter(this::hasChildrenUnder10)
    .collect(toList())

//...

private boolean female(Person p) { return p.getGender() == Female; }
private boolean hasChildrenUnder10(Person parent) {
    return parent.getChildren().stream()
                    .anyMatch(c -> c.getAge() < 10));
}

【讨论】:

  • +1 我仍然会将子过滤器重构为自己的函数,然后在此处使用方法引用。也许像filter(this::hasChildrenUnderTen) 这样的东西,只是为了在这种情况下使流更具可读性。
  • filter(pred).findAny().isPresent 的更简洁的替代品是 anyMatch(pred)
【解决方案2】:

您有 2 个for 循环,这意味着在某些时候您需要另一个流。在这里,当您致电map 时,您会将您的母亲映射到孩子的列表中。然后你就好像你有一个孩子的流,但实际上你有一个孩子的集合。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    • 1970-01-01
    • 2019-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多