在Java 8中,Stream.map()和Stream.flatMap()方法之间有什么区别?
当前回答
请仔细阅读这篇文章以获得一个清晰的概念,
map vs flatMap:
要从列表中返回每个单词的长度,我们将执行如下操作。
简短版本如下
当我们收集两个列表时,如下所示
没有flat map =>[1,2],[1,1] =>[[1,2],[1,1]]这里在一个列表中放置了两个列表,因此输出将是包含列表的列表
使用flat map =>[1,2],[1,1] =>[1,2,1,1],这里两个列表被平铺,只有值被放在列表中,因此输出将是只包含元素的列表
基本上,它将所有对象合并为一个
##详细版本已给出如下:-
例如:-考虑一个列表[" STACK ", " OOOVVVER "],我们试图返回一个列表像[" STACKOVER "](从该列表中只返回唯一的字母) 最初,我们将执行如下操作,从[" STACK ", " OOOVVVER "]返回一个列表[" STACKOVER "]
public class WordMap {
public static void main(String[] args) {
List<String> lst = Arrays.asList("STACK","OOOVER");
lst.stream().map(w->w.split("")).distinct().collect(Collectors.toList());
}
}
这里的问题是,传递给map方法的Lambda为每个单词返回一个字符串数组,因此map方法返回的流实际上是流类型,但我们需要的是流来表示字符流,下面的图像说明了这个问题。
图一:
你可能会想,我们可以用flatmap来解决这个问题,让我们看看如何用map和arrays。stream来解决这个问题 首先,你需要一个字符流而不是数组流。有一个叫做Arrays.stream()的方法,它将接受一个数组并生成一个流,例如:
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());
上面的方法仍然不起作用,因为我们现在得到了一个流的列表(更准确地说,流>)。相反,我们必须首先将每个单词转换为一个单独的字母数组,然后将每个数组转换为一个单独的流
通过使用flatMap,我们应该能够修复这个问题如下:
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());
flatMap不是用流而是用流的内容来映射每个数组。在使用map(Arrays::stream)时生成的所有单独流被合并成一个流。图B说明了使用flatMap方法的效果。将其与图A中的map进行比较。 图B
flatMap方法允许您用另一个流替换流的每个值,然后将所有生成的流连接到单个流中。
其他回答
我想举两个例子来说明更实际的观点: 第一个使用地图的例子:
@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);
}
在第一个例子中没有什么特别的,一个函数被应用来返回大写的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);
}
在第二个例子中,传递了一个List流。它不是一个整数流! 如果必须使用转换函数(通过map),则首先必须将流平展为其他类型的流(整数流)。 如果flatMap被移除,则返回以下错误:对于参数类型List, int,操作符+未定义。 不可能在整数列表上应用+ 1 !
简单的答案。
映射操作可以生成流的流。前流<流<整数> >
flatMap操作只会产生流。前流<整数>
如果你熟悉c#也可以很好的类比。基本上c# Select类似于java map和c# SelectMany java flatMap。对于集合,同样适用于Kotlin。
传递给流的函数。Map必须返回一个对象。这意味着输入流中的每个对象都会导致输出流中的一个对象。
传递给流的函数。flatMap为每个对象返回一个流。这意味着该函数可以为每个输入对象返回任意数量的对象(包括none)。然后将结果流连接到一个输出流。
流操作flatMap和map接受函数作为输入。
flatMap期望该函数为流的每个元素返回一个新的流,并返回一个流,该流结合了该函数为每个元素返回的流的所有元素。换句话说,使用flatMap,对于来自源的每个元素,函数将创建多个元素。http://www.zoftino.com/java-stream-examples#flatmap-operation
Map期望函数返回一个转换后的值,并返回一个包含转换后元素的新流。换句话说,使用map,对于来自源的每个元素,函数将创建一个转换后的元素。 http://www.zoftino.com/java-stream-examples#map-operation
推荐文章
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Jersey在未找到InjectionManagerFactory时停止工作
- 在Java流是peek真的只是调试?
- Recyclerview不调用onCreateViewHolder
- 将JSON字符串转换为HashMap