从 java 中的 lambda forEach() 返回

2022-08-31 08:58:23

我正在尝试将一些 for-each 循环更改为 lambda 方法,以发现 lambda 表达式的可能性。以下情况似乎是可能的:forEach()

ArrayList<Player> playersOfTeam = new ArrayList<Player>();      
for (Player player : players) {
    if (player.getTeam().equals(teamName)) {
        playersOfTeam.add(player);
    }
}

使用λforEach()

players.forEach(player->{if (player.getTeam().equals(teamName)) {playersOfTeam.add(player);}});

但是下一个不起作用:

for (Player player : players) {
    if (player.getName().contains(name)) {
        return player;
    }
}

与λ

players.forEach(player->{if (player.getName().contains(name)) {return player;}});

最后一行的语法是否有问题,或者是否无法从方法返回?forEach()


答案 1

从 lambda 表达式返回,而不是从包含方法返回。而不是你需要流:returnforEachfilter

players.stream().filter(player -> player.getName().contains(name))
       .findFirst().orElse(null);

此处将流限制为与谓词匹配的那些项,然后返回具有第一个匹配条目的 。filterfindFirstOptional

这看起来不如for-loop方法有效,但实际上可能会短路 - 它不会生成整个过滤流,然后从中提取一个元素,而是只过滤所需数量的元素,以便找到第一个匹配的元素。如果您不一定关心从(有序的)流中获取第一个匹配的播放器,而只是使用任何匹配的项目,也可以使用。这样可以在涉及并行性时提高效率。findFirst()findAny()findFirst()


答案 2

我建议您首先尝试从整体上理解Java 8,最重要的是,在您的情况下,它将是流,lambda和方法引用。

逐行将现有代码转换为 Java 8 代码,而应提取特征并转换这些特征。

我在你的第一个案例中发现如下:

  • 如果输入结构的元素与某些谓词匹配,则您希望将这些元素添加到输出列表中。

让我们看看我们如何做到这一点,我们可以通过以下方式做到这一点:

List<Player> playersOfTeam = players.stream()
    .filter(player -> player.getTeam().equals(teamName))
    .collect(Collectors.toList());

你在这里做的是:

  1. 将您的输入结构转换为流(我在这里假设它是类型,现在您有一个.Collection<Player>Stream<Player>
  2. 过滤掉所有不需要的元素,如果希望保留,则将每个玩家映射到布尔值 true。Predicate<Player>
  3. 通过 收集列表中的结果元素,在这里我们可以使用标准库收集器之一,即.CollectorCollectors.toList()

这还包含了另外两点:

  1. 针对接口编写代码,因此针对 over 编写代码。List<E>ArrayList<E>
  2. 对 中的类型参数使用菱形推断,毕竟您使用的是 Java 8。new ArrayList<>()

现在进入你的第二点:

您再次希望将一些遗留的Java转换为Java 8,而不考虑更大的图景。这部分已经由@IanRoberts回答,尽管我认为你需要按照他的建议去做。players.stream().filter(...)...