Java 8中的map和flatMap方法有什么区别?
在Java 8中, Stream.map
和Stream.flatMap
方法有什么区别?
map
和flatMap
都可以应用到Stream<T>
,它们都返回一个Stream<R>
。 区别在于map
操作为每个输入值生成一个输出值,而flatMap
操作为每个输入值生成任意数量(零个或多个)值。
这反映在每个操作的参数中。
map
操作接受一个Function
,该Function
为输入流中的每个值调用,并生成一个结果值,并将其发送到输出流。
flatMap
操作采用了一个函数,它在概念上想要消耗一个值并生成任意数量的值。 但是,在Java中,返回任意数量的值的方法很麻烦,因为方法只能返回零个或一个值。 我们可以想象一个API,其中flatMap
的mapper函数获取一个值并返回一个数组或值List
,然后将其发送到输出。 鉴于这是流库,表示任意数量返回值的一种特别合适的方式是映射器函数本身返回一个流! 由映射器返回的流的值从流中排出并传递到输出流。 每次调用映射器函数返回的值的“块”在输出流中根本不会被区分,因此输出被称为“平坦化”。
典型的用法是flatMap
的mapper函数返回Stream.empty()
如果它想要发送零值,或者如果Stream.of(a, b, c)
想返回多个值则返回。 当然,任何流都可以返回。
Stream.flatMap
,可以通过它的名字猜到,是map
和flat
操作的结合。 这意味着你首先对你的元素应用一个函数,然后将其平坦化。 Stream.map
仅将一个函数应用于流而不压扁流。
要理解什么是扁平化流,请考虑像[ [1,2,3],[4,5,6],[7,8,9] ]
这样的结构,它具有“两个层次”。 扁平化意味着将其转变为“一级”结构: [ 1,2,3,4,5,6,7,8,9 ]
。
我想举两个例子来获得更实际的观点:
使用地图的第一个示例:
@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);
}
在第一个例子中没有什么特别的, Function
应用于以大写字母返回String
。
使用flatMap
第二个示例:
@Test
public void testflatMap() throws Exception {
List<Integer> together = Stream.of(asList(1, 2), asList(3, 4)) // Stream of List<Integer>
.flatMap(List::stream)
.map(integer -> integer + 1)
.collect(Collectors.toList());
assertEquals(asList(2, 3, 4, 5), together);
}
在第二个例子中,传递了一个列表流。 它不是一个整数流!
如果必须使用变换函数(通过映射),那么首先必须将流平铺为其他内容(整数流)。
如果flatMap被移除,则返回以下错误: operator +未定义为参数类型List,int。
无法在整数列表中应用+1!
上一篇: What's the difference between map and flatMap methods in Java 8?