ChatGPT解决这个技术问题 Extra ChatGPT

从 java 中的 lambda forEach() 返回

我正在尝试将一些 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() 方法返回?

我还不太熟悉 lambdas 的内部结构,但是当我问自己这个问题:“你会从什么返回?”时,我最初的怀疑是它不是方法。
@Gimby是的,语句中的return从lambda本身返回,而不是从任何称为lambda的地方返回。提前终止流(“短路”)使用 findFirst,如 Ian Roberts' answer 所示。

I
Ian Roberts

那里的 return 从 lambda 表达式返回,而不是从包含方法返回。您需要 filter 流而不是 forEach

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

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

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


谢谢,这就是我要找的! Java8 中似乎有很多新的东西需要探索 :)
合理,但我建议您不要在 Optional 上使用 orElse(null)Optional 的要点是提供一种方法来指示值的存在或不存在,而不是重载 null(这会导致 NPE)。如果您使用 optional.orElse(null),它会收回所有与 null 相关的问题。只有当你不能修改调用者并且它真的期待一个空值时,我才会使用它。
@StuartMarks 确实,将方法返回类型修改为 Optional<Player> 将是一种更自然的方式来适应流范式。我只是想展示如何使用 lambdas 复制现有行为。
对于(部分部分:部分)如果(!part.isEmpty())返回false;我想知道什么是真正更短的。并且更清晰。 java流api真正破坏了java语言和java环境。 2020 年在任何 Java 项目中工作的噩梦。
C
Community

我建议您首先尝试从整体上理解 Java 8,对您而言最重要的是流、lambda 和方法引用。

您永远不应该将现有代码逐行转换为 Java 8 代码,您应该提取特征并进行转换。

我在您的第一个案例中确定的内容如下:

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

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

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

你在这里做的是:

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

这还包含另外两点:

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

现在到你的第二点:

您再次希望将旧版 Java 转换为 Java 8,而无需考虑全局。 @IanRoberts已经回答了这部分,但我认为您需要按照他的建议做players.stream().filter(...)...


S
Sri

如果你想返回一个布尔值,那么你可以使用这样的东西(比过滤器快得多):

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

y
ybonda

这对我有帮助:

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

取自 Java 8 Finding Specific Element in List with Lambda


n
nabster

你也可以抛出异常:

笔记:

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

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

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