一个 lambda 参数,其中 T 是元素,R 是使用 T 构建的返回元素。最后,我们将拥有一个带有 R 类型对象的 Stream。一个简单的例子可以是:
Stream
.of(1,2,3,4,5)
.map(myInt -> "preFix_"+myInt)
.forEach(System.out::println);
它只需要类型 Integer 的元素 1 到 5,使用每个元素从类型 String 构建一个值为 "prefix_"+integer_value 的新元素并将其打印出来。
flatMap()
知道 flatMap() 采用函数 F<T, R> where 是很有用的
-
T 是一种来自的类型,可以从中/使用它来构建流。它可以是列表 (T.stream())、数组 (Arrays.stream(someArray)) 等。Stream 可以包含/或形成的任何内容。在下面的示例中,每个开发人员都有多种语言,因此 dev. Languages 是一个 List,将使用 lambda 参数。
-
R 是将使用 T 构建的结果流。知道我们有许多 T 实例,我们自然会有许多来自 R 的流。来自类型 R 的所有这些流现在将合并为一个 来自 Type R 的单个“扁平”流。
示例
Bachiri Taoufiq [在此处查看其答案]1 的示例简单易懂。为了清楚起见,假设我们有一个开发团队:
dev_team = {dev_1,dev_2,dev_3}
,每个开发人员都了解多种语言:
dev_1 = {lang_a,lang_b,lang_c},
dev_2 = {lang_d},
dev_3 = {lang_e,lang_f}
在 dev_team 上应用 Stream.map() 以获取每个开发者的语言:
dev_team.map(dev -> dev.getLanguages())
会给你这个结构:
{
{lang_a,lang_b,lang_c},
{lang_d},
{lang_e,lang_f}
}
基本上是List<List<Languages>> /Object[Languages[]]。不是很漂亮,也不是像 Java8 的!!
使用Stream.flatMap(),您可以“扁平化”事物,因为它采用上述结构
并转成{lang_a, lang_b, lang_c, lang_d, lang_e, lang_f},基本可以当成List<Languages>/Language[]/etc...
所以最后,你的代码会像这样更有意义:
dev_team
.stream() /* {dev_1,dev_2,dev_3} */
.map(dev -> dev.getLanguages()) /* {{lang_a,...,lang_c},{lang_d}{lang_e,lang_f}}} */
.flatMap(languages -> languages.stream()) /* {lang_a,...,lang_d, lang_e, lang_f} */
.doWhateverWithYourNewStreamHere();
或者简单地说:
dev_team
.stream() /* {dev_1,dev_2,dev_3} */
.flatMap(dev -> dev.getLanguages().stream()) /* {lang_a,...,lang_d, lang_e, lang_f} */
.doWhateverWithYourNewStreamHere();
何时使用 map() 和使用 flatMap():
-
当流中的每个 T 类型元素都应该映射/转换为 R 类型的 单个 元素时,请使用 map()。结果是类型为 (1开始元素 -> 1 个结束元素) 并返回 R 类型的新元素流。
-
当流中的每个 T 类型元素都应该映射/转换为 R 类型元素的 Collections 时,请使用 flatMap()。结果是类型为 (1开始元素 -> n 个结束元素)。然后将这些集合合并(或展平)到新的 R 类型元素流。这对于表示 嵌套循环 非常有用。
Java 8 之前:
List<Foo> myFoos = new ArrayList<Foo>();
for(Foo foo: myFoos){
for(Bar bar: foo.getMyBars()){
System.out.println(bar.getMyName());
}
}
发布 Java 8
myFoos
.stream()
.flatMap(foo -> foo.getMyBars().stream())
.forEach(bar -> System.out.println(bar.getMyName()));