在Java 8中,Stream.map()和Stream.flatMap()方法之间有什么区别?
当前回答
传递给流的函数。Map必须返回一个对象。这意味着输入流中的每个对象都会导致输出流中的一个对象。
传递给流的函数。flatMap为每个对象返回一个流。这意味着该函数可以为每个输入对象返回任意数量的对象(包括none)。然后将结果流连接到一个输出流。
其他回答
请仔细阅读这篇文章以获得一个清晰的概念,
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 !
.map用于A -> B映射
Stream.of("dog", "cat") // stream of 2 Strings
.map(s -> s.length()) // stream of 2 Integers: [3, 3]
它将任意项A转换为任意项b
.flatMap用于A ->流< B>连接
Stream.of("dog", "cat") // stream of 2 Strings
.flatMapToInt(s -> s.chars()) // stream of 6 ints: [d, o, g, c, a, t]
it——1将任何项A转换为Stream< B>,然后——2将所有流连接到一个(平面)流。Javadoc
注1:虽然后面的例子是一个原语流(IntStream),而不是一个对象流(stream),但它仍然说明了. flatmap的思想。
注意2:尽管有这个名字,String.chars()方法返回的是整数。所以实际的集合将是:[100,111,103,99,97,116] ,其中100是“d”的代码,111是“o”的代码,等等。同样,为了说明目的,它被表示为[d, o, g, c, a, t]。
如果你熟悉c#也可以很好的类比。基本上c# Select类似于java map和c# SelectMany java flatMap。对于集合,同样适用于Kotlin。
如果您认为map()是一个迭代(一级for循环),那么flatmap()是一个两级迭代(类似于嵌套的for循环)。(输入每个迭代元素foo,然后执行foo. getbarlist()并再次迭代该barList)
Map():获取一个流,对每个元素做一些事情,收集每个进程的单个结果,输出另一个流。“做一些函数”的定义是隐含的。如果任何元素的处理结果为null,则使用null来组成最终流。因此,结果流中的元素数量将等于输入流的数量。
Flatmap():获取元素/流流和函数(显式定义)的流,将函数应用到每个流的每个元素,并将所有中间结果流收集为更大的流(“扁平化”)。如果任何元素的处理结果为null,则为“扁平化”的最后一步提供空流。如果输入是几个流,则结果流中的元素数量是所有输入中所有参与元素的总和。
推荐文章
- 在流中使用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