使用转换进行迭代
此页面由 Venkat Subramaniam 在 UPL 下贡献在迭代时进行转换
在本系列的 教程 中,我们研究了如何将命令式风格中带有 if
或条件语句的循环转换为函数式风格。在本文中,我们将了解如何将命令式风格的迭代转换为函数式风格,该迭代会转换数据。此外,我们还将重构将转换数据与在转换之前选择特定元素的代码混合在一起的代码。
在命令式风格循环中转换数据时,我们可以在函数式风格中使用 map()
函数。让我们看看如何操作。
从命令式风格到函数式风格
以下是一个使用 foreach
进行迭代的示例,该示例将名称集合转换为大写
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
for(String name: names) {
System.out.println(name.toUpperCase());
}
在每次迭代中,name
变量都会绑定到一个新值。当迭代从给定集合中的一个元素前进到下一个元素时,每个名称都会使用 toUpperCase()
函数转换为大写,并将结果值打印出来。在上一篇文章中,我们已经了解了如何将命令式风格的 foreach
转换为函数式风格——使用 stream()
内部迭代。如果我们仅仅应用之前所见的内容,那么得到的函数式风格代码将非常笨拙,传递给 forEach
的 lambda 会同时执行转换和打印,如下所示
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
names.forEach(name -> System.out.println(name.toUpperCase())); //Don't do this
尽管上面的函数式风格代码将产生与命令式风格代码相同的结果,但传递给 forEach()
函数的 lambda 不连贯,难以阅读,也难以更改。
在将上面的命令式风格代码重构为函数式风格之前,我们应该首先将命令式风格重构为另一种命令式风格实现,以使每行代码更加连贯,如下所示
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
for(String name: names) {
String nameInUpperCase = name.toUpperCase();
System.out.println(nameInUpperCase);
}
从本系列的上一篇文章中,我们知道 for
可以转换为 stream()
,并且值的打印可以在 forEach()
内部完成。这留下了转换,即对 toUpperCase()
函数的调用。这种转换可以使用 stream()
上的 map()
操作来完成。
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
names.stream()
.map(name -> name.toUpperCase())
.forEach(nameInUpperCase -> System.out.println(nameInUpperCase));
map()
操作根据传递给 map()
的 lambda 表达式中调用的函数,将数据转换为不同的值。在本例中,每个名称都转换为其大写值。然后,在传递给 forEach()
的 lambda 表达式中打印出转换后的值。
我们可以使用方法引用而不是 lambda 表达式使代码更加简洁,如下所示
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
names.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
使用 map()
函数在迭代数据集合时转换数据。
选择要转换的元素
假设在迭代过程中,我们想根据某个条件从集合中选择一些值,并仅对这些元素应用转换。例如,如果我们想转换并打印长度为 4 的名称怎么办?在命令式风格中,我们可以执行以下操作
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
for(String name: names) {
if(name.length() == 4) {
System.out.println(name.toUpperCase());
}
}
我们已经知道命令式风格的 if
可以重构为函数式风格中的 filter()
函数。我们可以在 filter()
操作之后执行转换,使用 map()
,如下所示
List<String> names = List.of("Jack", "Paula", "Kate", "Peter");
names.stream()
.filter(name -> name.length() == 4)
.map(String::toUpperCase)
.forEach(System.out::println);
filter()
函数会丢弃不需要的数据,只传递我们想要使用的值。map()
函数会转换它在过滤器之后看到的那些值。
映射
在 for 循环中看到数据转换的任何地方,都使用 map()
函数在函数式风格中执行转换。此外,如果循环体包含一个 if
语句来选择某些值进行转换,那么在使用 map()
方法之前,使用 stream()
API 调用 filter()
方法。
上次更新: 2024 年 1 月 8 日