@Test
public void convertStringToUpperCaseStreams() {
List<String> collected = Stream.of("a", "b", "hello") // Stream of String
.map(String::toUpperCase) // Returns a stream consisting of the results of applying the given function to the elements of this stream.
.collect(Collectors.toList());
assertEquals(asList("A", "B", "HELLO"), collected);
}
在第二个示例中,传递了List of List . It is NOT a Stream of Integer! If a transformation Function has to be used (through map), then first the Stream has to be flattened to something else (a Stream of Integer). 如果删除flatMap,则返回以下错误: The operator + is undefined for the argument type(s) List, int. 无法在整数列表中应用1!
String[] arrayOfWords = {"STACK", "OOOVVVER"};
Stream<String> streamOfWords = Arrays.stream(arrayOfWords);
streamOfWords.map(s->s.split("")) //Converting word in to array of letters
.map(Arrays::stream).distinct() //Make array in to separate stream
.collect(Collectors.toList());
By using flatMap we should be able to fix this problem as below:
String[] arrayOfWords = {"STACK", "OOOVVVER"};
Stream<String> streamOfWords = Arrays.stream(arrayOfWords);
streamOfWords.map(s->s.split("")) //Converting word in to array of letters
.flatMap(Arrays::stream).distinct() //flattens each generated stream in to a single stream
.collect(Collectors.toList());
17 回答
map
和flatMap
都可以应用于Stream<T>
并且它们都返回Stream<R>
. 不同之处在于map
操作为每个输入值生成一个输出值,而flatMap
操作为每个输入值生成任意数量(零个或多个)值 .这反映在每个操作的参数中 .
map
操作采用Function
,为输入流中的每个值调用它并生成一个结果值,该值将发送到输出流 .flatMap
操作采用一个概念上想要消耗一个值并产生任意数量的值的函数 . 但是,在Java中,返回任意数量的值的方法很麻烦,因为方法只能返回零个或一个值 . 可以想象一个API,其中flatMap
的映射器函数获取一个值并返回一个数组或List
的值,然后将其发送到输出 . 鉴于这是流库,一种表示任意数量的返回值的特别方法是mapper函数本身返回一个流!映射器返回的流中的值将从流中排出并传递到输出流 . 每个调用mapper函数返回的"clumps"值在输出流中根本没有区分,因此输出据说是"flattened."典型的用途是
flatMap
的映射器函数如果要发送零值则返回Stream.empty()
,如果想要返回多个值,则返回Stream.of(a, b, c)
. 但是当然可以返回任何流 .Stream.flatMap
,因为它的名字可以猜到,是map
和flat
操作的组合 . 这意味着您首先将一个函数应用于您的元素,然后将其展平 .Stream.map
仅在不对流进行展平的情况下将函数应用于流 .要了解流整合的内容,请考虑像
[ [1,2,3],[4,5,6],[7,8,9] ]
这样的结构,它具有"two levels" . 展平这意味着将其转换为"one level"结构:[ 1,2,3,4,5,6,7,8,9 ]
.我想举两个例子来获得更实际的观点:
第一个使用 Map 的例子:
在第一个示例中没有任何特殊内容,
Function
用于以大写形式返回String
.使用
flatMap
的第二个例子:在第二个示例中,传递了List of List . It is NOT a Stream of Integer!
If a transformation Function has to be used (through map), then first the Stream has to be flattened to something else (a Stream of Integer).
如果删除flatMap,则返回以下错误: The operator + is undefined for the argument type(s) List, int.
无法在整数列表中应用1!
Map: - 此方法将一个Function作为参数,并返回一个新流,该流包含通过将传递的函数应用于流的所有元素而生成的结果 .
让我们假设,我有一个整数值列表(1,2,3,4,5)和一个函数接口,其逻辑是传递的整数的平方 . (e - > e * e) .
输出: -
如您所见,输出是一个新流,其值是输入流的值的平方 .
http://codedestine.com/java-8-stream-map-method/
FlatMap: - 此方法将一个Function作为参数,此函数接受一个参数T作为输入参数,并返回一个参数R流作为返回值 . 当此函数应用于此流的每个元素时,它会生成一个新值流 . 然后将每个元素生成的这些新流的所有元素复制到新流中,该流将是此方法的返回值 .
我们的图像,我有一个学生对象列表,每个学生可以选择多个科目 .
输出: -
如您所见,输出是一个新流,其值是输入流的每个元素返回的流的所有元素的集合 .
[S1,S2,S3] - > [{“历史”,“数学”,“地理”},{“经济学”,“生物学”},{“科学”,“数学”}] - >采取独特的科目 - > [经济学,生物学,地理学,科学,历史,数学]
http://codedestine.com/java-8-stream-flatmap-method/
Please go through the post fully to get a clear idea, map vs flatMap: 要从列表中返回每个单词的长度,我们会执行以下操作 .
For example:-
考虑一个列表 [“STACK”, ”OOOVVVER”] ,我们试图返回一个像 [“STACKOVER”] 这样的列表(只返回该列表中的唯一字母)最初,我们会做类似下面的事情从 [“STACK”, ”OOOVVVER”] 返回一个列表 [“STACKOVER”]
这里的问题是,Lambda传递给map方法为每个单词返回一个String数组,所以map方法返回的流实际上是Stream类型,但我们需要的是Stream来表示一个字符流,下面的图片说明了问题 .
Figure A:
您可能会认为,我们可以使用flatmap解决此问题,
好的,让我们看看如何通过使用map和Arrays.stream来解决这个问题 . 首先,你需要一个字符流而不是数组流 . 有一个名为Arrays.stream()的方法可以获取一个数组并生成一个流,例如:
上面仍然不起作用,因为我们现在最终得到一个流列表(更确切地说,Stream>),相反,我们必须首先将每个单词转换为单个字母的数组,然后将每个数组转换为单独的流
By using flatMap we should be able to fix this problem as below:
flatMap将执行不是使用流而是使用该流的内容映射每个数组 . 使用map(Arrays :: stream)时生成的所有单个流都会合并到一个流中 . 图B说明了使用flatMap方法的效果 . 将它与图A中的 Map 进行比较. Figure B
The flatMap method lets you replace each value of a stream with another stream and then joins all the generated streams into a single stream.
传递给
stream.map
的函数必须返回一个对象 . 这意味着输入流中的每个对象都会在输出流中生成一个对象 .传递给
stream.flatMap
的函数返回每个对象的流 . 这意味着该函数可以为每个输入对象返回任意数量的对象(包括无) . 然后将得到的流连接到一个输出流 .One line answer: flatMap helps to flatten a Collection<Collection<T>> into a Collection<T> . 以同样的方式,它也会将 Optional<Optional<T>> 压平为 Optional<T> .
如您所见,仅使用 map() :
中间类型是
Stream<List<Item>>
返回类型是
List<List<Item>>
和 flatMap() :
中间类型是
Stream<Item>
返回类型是
List<Item>
这是下面使用的代码中的 test result :
Code used :
对于Map,我们有一个元素列表和一个(函数,动作)f,所以:
对于平面 Map ,我们有一个元素列表列表,我们有一个(函数,动作)f,我们希望结果被展平:
我有一种感觉,这里的大多数答案都使这个简单问题复杂化 . 如果您已经了解
map
的工作原理应该相当容易掌握 .在使用
map()
时,有些情况下我们可能会遇到不需要的嵌套结构,flatMap()
方法旨在通过避免包装来克服这个问题 .例子:
1
我们可以通过使用
flatMap
避免使用嵌套列表:2
哪里:
Oracle关于Optional的文章强调了map和flatmap之间的区别:
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
我不太确定我应该回答这个问题,但每当我遇到一个不理解这一点的人时,我都会使用相同的例子 .
想象一下,你有一个苹果 . 例如,
map
正在将该苹果转换为apple-juice
或一对一映射 .拿同一个苹果,只取出它的种子,这就是
flatMap
做的,或者一对多,一个苹果作为输入,许多种子作为输出 .map() and flatMap()
map()
只需要一个函数一个lambda参数,其中T是元素,R是使用T构建的返回元素 . 最后我们将得到一个带有类型R对象的Stream . 一个简单的例子可以是:
它只需要类型
Integer
的元素1到5,使用每个元素从类型String
构建一个值为"prefix_"+integer_value
的新元素并将其打印出来 .flatMap()
知道flapMap()采用函数
F<T, R>
在哪里很有用T是可以从中构建Stream的类型 . 它可以是List(T.stream()),数组(Arrays.stream(someArray))等 . 来自的任何东西流可以与/或形成 . 在下面的例子中,每个开发人员都有很多语言,所以dev . 语言是一个List,将使用lambda参数 .
R是将使用T构建的结果Stream . 知道我们有很多T实例,我们自然会有很多来自R的Streams . 来自Type R的所有这些Streges将 now be combined into one 单个'flat'来自Type R的Stream .
Example
Bachiri Taoufiq see its answer here的例子简单易懂 . 为了清楚起见,我们假设我们有一个开发团队:
,每个开发人员都知道多种语言:
在dev_team上应用Stream.map()以获取每个开发人员的语言:
会给你这个结构:
这基本上是
List<List<Languages>> /Object[Languages[]]
. 不是很漂亮,也不像Java8!使用
Stream.flatMap()
,您可以'flatten'因为它采用上述结构并将其转换为
{lang_a, lang_b, lang_c, lang_d, lang_e, lang_f}
,基本上可以用作List<Languages>/Language[]/ect
...所以你的代码结束会更有意义:
或者干脆:
When to use map() and use flatMap() :
当流中的T类型的每个元素都被映射/转换为R类型的单个元素时,使用
map()
. 结果是类型(1个开始元素 - > 1个结束元素)和新的元素流的映射 . 返回类型R.当您的流中的T类型的每个元素都应该映射/转换为R类型的元素集合时,使用
flatMap()
. 结果是类型的映射(1个起始元素 - > n个结束元素) . 然后将这些集合合并(或展平)为R类型的新元素流 . 例如,这可用于表示 nested loops .前Java 8:
发布Java 8
如果您熟悉,也可以使用C#进行类比 . 基本上C#
Select
类似于javamap
和C#SelectMany
javaflatMap
. 同样适用于Kotlin的收藏品 .这对初学者来说非常困惑 . 基本区别是
map
为列表中的每个条目发出一个项目,flatMap
基本上是map
flatten
操作 . 更清楚的是,当需要多个值时使用flatMap,例如,当您期望循环返回数组时,flatMap在这种情况下将非常有用 .我写了一篇关于此的博客,你可以查看here .
流操作
flatMap
和map
接受函数作为输入 .flatMap
期望函数为流的每个元素返回一个新流,并返回一个流,该流组合了每个元素的函数返回的流的所有元素 . 换句话说,对于flatMap
,对于源中的每个元素,函数将创建多个元素 . http://www.zoftino.com/java-stream-examples#flatmap-operationmap
期望函数返回转换后的值并返回包含已转换元素的新流 . 换句话说,对于map
,对于源中的每个元素,函数将创建一个变换元素 . http://www.zoftino.com/java-stream-examples#map-operationflatMap()
也利用了对流的部分惰性评估 . 它将读取第一个流,只有在需要时才会进入下一个流 . 这里详细解释了这种行为:Is flatMap guaranteed to be lazy?假设我们有:
flatMap
让我们接受一个接受一个参数的
Function
并产生一个Stream
的值:并将此函数应用于每个列表:
这正是Stream.flatMap可以做的:
Map
让我们接受一个接受一个参数并产生一个值的
Function
:并将此函数应用于每个列表:
这正是Stream.map可以做的: