从 java 中的 lambda for each()返回

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

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

用的是 Lambda forEach()

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

但是下一个不起作用:

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

和 Lambda 一起

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

最后一行的语法有什么问题吗? 或者不可能从 forEach()方法返回?

195482 次浏览

The return there is returning from the lambda expression rather than from the containing method. Instead of forEach you need to filter the stream:

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

在这里,filter将流限制为与谓词匹配的项,然后 findFirst返回带有第一个匹配项的 Optional

This looks less efficient than the for-loop approach, but in fact findFirst() can short-circuit - it doesn't generate the entire filtered stream and then extract one element from it, rather it filters only as many elements as it needs to in order to find the first matching one. You could also use findAny() instead of findFirst() if you don't necessarily care about getting the first matching player from the (ordered) stream but simply any matching item. This allows for better efficiency when there's parallelism involved.

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

您应该逐行地将现有代码转换为 Java8代码,您应该提取特性并转换它们。

我在你的第一个案子中发现了以下内容:

  • 如果输入结构的元素与某些谓词匹配,则需要将它们添加到输出列表中。

让我们看看我们如何做到这一点,我们可以做到以下几点:

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

你在这里要做的是:

  1. 将您的输入结构转换为流(我在这里假设它是 Collection<Player>类型,现在您有了 Stream<Player>
  2. Filter out all unwanted elements with a Predicate<Player>, mapping every player to the boolean true if it is wished to be kept.
  3. 通过 Collector在列表中收集结果元素,这里我们可以使用标准库收集器之一 Collectors.toList()

这还包括另外两点:

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

现在谈谈你的第二个观点:

You again want to convert something of legacy Java to Java 8 without looking at the bigger picture. This part has already been answered by @IanRoberts, though I think that you need to do players.stream().filter(...)... over what he suggested.

这对我有所帮助:

List<RepositoryFile> fileList = response.getRepositoryFileList();
RepositoryFile file1 = fileList.stream().filter(f -> f.getName().contains("my-file.txt")).findFirst().orElse(null);

取自 用 Lambda 查找 List 中的特定元素

If you want to return a boolean value, then you can use something like this (much faster than filter):

players.stream().anyMatch(player -> player.getName().contains(name));

还可以引发异常:

Note:

为了便于阅读,流的每个步骤都应该在新的一行中列出。

players.stream()
.filter(player -> player.getName().contains(name))
.findFirst()
.orElseThrow(MyCustomRuntimeException::new);

如果您的逻辑是松散的“异常驱动”,例如在您的代码中有一个地方可以捕获所有异常并决定下一步做什么。只有在可以避免多个 try-catch占用代码库并抛出这些异常的情况下,才使用异常驱动的开发,这些异常是针对 非常特殊情况的,而且是可以正确处理的。)