我有以下for循环:
List<Player> players = new ArrayList<>();
for (Team team : teams) {
ArrayList<TeamPlayer> teamPlayers = team.getTeamPlayers();
for (teamPlayer player : teamPlayers) {
players.add(new Player(player.getName, player.getPosition());
}
}
,我正试图将其转换为流:
List<Player> players = teams.forEach(t -> t.getTeamPlayers()
.forEach(p -> players.add(new Player(p.getName(), p.getPosition())))
);
但是我得到一个编译错误:
variable 'players' might not have been initialized
为什么会发生这种情况?也许有另一种方法来创建流,我正在考虑使用flatMap
,但不确定如何应用它。
首先,您需要了解Streams不
因此,不要试图模仿循环。检查API提供的工具。操作forEach()
用于特殊情况,当您需要执行副作用,而不是时以便将流中的元素累积到Collection中。
注意:对于teams.forEach()
,您实际上不是在使用流,而是方法Iterable.forEach()
,该方法可用于Iterable
的每个实现。
为了在流上执行缩减,我们有几个专门的操作,如collect
,reduce
等(更多信息参见API文档- reduction)。
collect()
操作意味着执行可变约简。您可以通过提供内置CollectorCollectors.toList()
作为参数来将数据收集到列表中。由于Java 16操作toList()
被引入到API中,它是在toArray()
操作的基础上实现的,并且比同名收集器性能更好(因此,如果您的JDK版本允许您使用它,它是首选选项)。
我正在考虑使用
flatMap
,但不确定如何应用它。
操作flatMap()
意味着执行一对多转换。它期望有一个函数,该函数接受一个流元素并生成结果类型的流,生成的流的元素将替代初始元素。
注意:使用尽可能少的操作来编写流的通用方法(因为函数式编程给Java带来的主要优势之一就是简单)。出于这个原因,当流元素在单步中生成Collection时应用 更排序。这就是实现的样子:flatMap()
是习惯做法,因为它比分两步执行map().flatMap()
List<Team> teams = List.of();
List<Player> players = teams.stream() // Stream<Team>
.flatMap(team -> team.getTeamPlayers().stream()) // Stream<Player>
.map(player -> new Player(player.getName(), player.getPosition()))
.toList(); // for Java 16+ or collect(Collectors.toList())
这基本上是Alexander Ivanchenko的答案,但有方法参考。
final var players = teams.stream()
.map(Team::getTeamPlayers)
.flatMap(Collection::stream)
.map(p -> new Player(p.getName(), p.getPosition()))
.toList();
如果你的Player
类有一个工厂方法(取决于Player
和TeamPlayer
之间的关系:
public static Player fromTeamPlayer(final TeamPlayer teamPlayer) {
return new Player(teamPlayer.getName(), teamPlayer.getPosition());
}
你可以进一步简化为:
final var players = teams.stream()
.map(Team::getTeamPlayers)
.flatMap(Collection::stream)
.map(Player::fromTeamPlayer)
.toList();