在java中从lambda forEach()返回

时间:2014-05-01 11:46:00

标签: java foreach lambda java-8 return-type

我正在尝试将一些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;
    }
}

with lambda

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

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

5 个答案:

答案 0 :(得分:89)

return从lambda表达式而不是contains方法返回。您需要forEach来代替filter

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

此处filter将流限制为与谓词匹配的项,然后findFirst会返回带有第一个匹配条目的Optional

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

答案 1 :(得分:11)

我建议你首先尝试在整个图片中理解Java 8,最重要的是在你的情况下它将是stream,lambdas和方法引用。

你应该从不逐行地将现有代码转换为Java 8代码,你应该提取功能并转换它们。

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

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

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

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

你在这里做的是:

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

    1. 针对接口的代码,因此针对List<E>的代码超过ArrayList<E>
    2. new ArrayList<>()中的类型参数使用菱形推理,毕竟您使用的是Java 8.
    3. 现在进入第二点:

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

答案 2 :(得分:4)

这对我有所帮助:

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

答案 3 :(得分:4)

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

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

答案 4 :(得分:1)

您还可以引发异常:

注意:

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

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

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