cas*_*lin 632 java java-8 java-stream
在Java 8中,Stream.map()和Stream.flatMap()方法有什么区别?
Stu*_*rks 745
双方map并flatMap可以应用到Stream<T>他们都返回Stream<R>.不同之处在于map操作为每个输入值生成一个输出值,而flatMap操作为每个输入值生成任意数量(零个或多个)值.
这反映在每个操作的参数中.
该map操作采用a Function,为输入流中的每个值调用,并生成一个结果值,该值将发送到输出流.
该flatMap操作采用概念上想要消耗一个值并产生任意数量的值的函数.但是,在Java中,返回任意数量的值的方法很麻烦,因为方法只能返回零或一个值.可以想象一个API,其中mapper函数flatMap获取值并返回一个数组或一个List值,然后将其发送到输出.鉴于这是流库,一种表示任意数量的返回值的特别方法是mapper函数本身返回一个流!映射器返回的流中的值将从流中排出并传递到输出流.每次调用mapper函数返回的值的"丛"在输出流中根本不被区分,因此输出被称为"扁平化".
典型用途是用于映射函数的flatMap返回Stream.empty(),如果要发送零个值,或者类似的东西Stream.of(a, b, c),如果要返回几个值.但是当然可以返回任何流.
Dic*_*ici 390
Stream.flatMap,因为它的名字可以猜到,是一个map和一个flat操作的组合.这意味着您首先将一个函数应用于元素,然后将其展平.Stream.map仅在不对流进行展平的情况下将函数应用于流.
要了解流的扁平化,请考虑[ [1,2,3],[4,5,6],[7,8,9] ]具有"两个级别"的结构.扁平化这意味着将其转换为"一级"结构:[ 1,2,3,4,5,6,7,8,9 ].
Rud*_*ers 215
我想举两个例子来得到一个更实际的观点:
第一个例子使用map:
@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);
}
Run Code Online (Sandbox Code Playgroud)
在第一个例子中没有什么特别的,a 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);
}
Run Code Online (Sandbox Code Playgroud)
在第二个示例中,传递了List of List.它不是整数流!
如果必须使用转换函数(通过映射),则首先必须将Stream展平为其他内容(整数流).
如果删除了flatMap,则返回以下错误:对于参数类型List,int,运算符+未定义.
无法在整数列表中应用+ 1!
Tec*_*Dog 150
请完整阅读帖子以获得一个清晰的想法,
map vs flatMap:
要从列表中返回每个单词的长度,我们会执行以下操作.
例如: -
考虑一个列表["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());
}
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是,Lambda传递给map方法为每个单词返回一个String数组,所以map方法返回的流实际上是Stream类型,但我们需要的是Stream来表示一个字符流,下面的图片说明了问题.
图A:
您可能会认为,我们可以使用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());
Run Code Online (Sandbox Code Playgroud)
上面仍然不起作用,因为我们现在最终得到一个流列表(更确切地说,Stream>),相反,我们必须首先将每个单词转换为单个字母的数组,然后将每个数组转换为单独的流
通过使用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());
Run Code Online (Sandbox Code Playgroud)
flatMap将执行不是使用流而是使用该流的内容映射每个数组.使用map(Arrays :: stream)时生成的所有单个流都会合并到一个流中.图B说明了使用flatMap方法的效果.将其与图A中的映射进行比较.
图B.

flatMap方法允许您将流的每个值替换为另一个流,然后将所有生成的流连接到单个流中.
nxh*_*oaf 87
一号线答案:flatMap有助于展平Collection<Collection<T>>成Collection<T>.以同样的方式,它也将压扁的Optional<Optional<T>>进入Optional<T>.
如你所见,map()只有:
Stream<List<Item>>List<List<Item>>并与flatMap():
Stream<Item>List<Item>这是下面使用的代码的测试结果:
-------- Without flatMap() -------------------------------
collect() returns: [[Laptop, Phone], [Mouse, Keyboard]]
-------- With flatMap() ----------------------------------
collect() returns: [Laptop, Phone, Mouse, Keyboard]
Run Code Online (Sandbox Code Playgroud)
使用的代码:
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
public class Parcel {
String name;
List<String> items;
public Parcel(String name, String... items) {
this.name = name;
this.items = Arrays.asList(items);
}
public List<String> getItems() {
return items;
}
public static void main(String[] args) {
Parcel amazon = new Parcel("amazon", "Laptop", "Phone");
Parcel ebay = new Parcel("ebay", "Mouse", "Keyboard");
List<Parcel> parcels = Arrays.asList(amazon, ebay);
System.out.println("-------- Without flatMap() ---------------------------");
List<List<String>> mapReturn = parcels.stream()
.map(Parcel::getItems)
.collect(Collectors.toList());
System.out.println("\t collect() returns: " + mapReturn);
System.out.println("\n-------- With flatMap() ------------------------------");
List<String> flatMapReturn = parcels.stream()
.map(Parcel::getItems)
.flatMap(Collection::stream)
.collect(Collectors.toList());
System.out.println("\t collect() returns: " + flatMapReturn);
}
}
Run Code Online (Sandbox Code Playgroud)
epo*_*pox 40
A -> B映射Stream.of("dog", "cat") // stream of 2 Strings
.map(s -> s.length()) // stream of 2 Integers: [3, 3]
Run Code Online (Sandbox Code Playgroud)
它将任何项目转换A为任何项目B。Javadoc
A -> Stream< B>连接Stream.of("dog", "cat") // stream of 2 Strings
.flatMapToInt(s -> s.chars()) // stream of 6 ints: [d, o, g, c, a, t]
Run Code Online (Sandbox Code Playgroud)
它 --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]。
Phi*_*ipp 38
传递给的函数stream.map必须返回一个对象.这意味着输入流中的每个对象都会在输出流中生成一个对象.
传递的函数stream.flatMap返回每个对象的流.这意味着该函数可以为每个输入对象返回任意数量的对象(包括无).然后将得到的流连接到一个输出流.
Bac*_*man 28
对于Map,我们有一个元素列表和一个(函数,动作)f,所以:
[a,b,c] f(x) => [f(a),f(b),f(c)]
Run Code Online (Sandbox Code Playgroud)
对于平面地图,我们有一个元素列表列表,我们有一个(函数,动作)f,我们希望结果被展平:
[[a,b],[c,d,e]] f(x) =>[f(a),f(b),f(c),f(d),f(e)]
Run Code Online (Sandbox Code Playgroud)
Grz*_*rek 25
我有一种感觉,这里的大多数答案都使这个简单问题复杂化.如果您已经了解了map应该相当容易掌握的作品.
在某些情况下,我们可以在使用时结束不需要的嵌套结构map(),该flatMap()方法旨在通过避免包装来克服这个问题.
例子:
List<List<Integer>> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3))
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
我们可以通过以下方式避免使用嵌套列表flatMap:
List<Integer> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3))
.flatMap(i -> i.stream())
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
Optional<Optional<String>> result = Optional.of(42)
.map(id -> findById(id));
Optional<String> result = Optional.of(42)
.flatMap(id -> findById(id));
Run Code Online (Sandbox Code Playgroud)
哪里:
private Optional<String> findById(Integer id)
Run Code Online (Sandbox Code Playgroud)
Rus*_*ore 20
Oracle关于Optional的文章强调了map和flatmap之间的区别:
String version = computer.map(Computer::getSoundcard)
.map(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
Run Code Online (Sandbox Code Playgroud)
不幸的是,这段代码无法编译.为什么?变量计算机属于类型
Optional<Computer>,因此调用map方法是完全正确的.但是,getSoundcard()返回Optional类型的对象.这意味着map操作的结果是类型的对象Optional<Optional<Soundcard>>.因此,对getUSB()的调用无效,因为最外面的Optional包含另一个Optional作为其值,当然这不支持getUSB()方法.对于流,flatMap方法将函数作为参数,返回另一个流.此函数应用于流的每个元素,这将导致流的流.但是,flatMap具有用该流的内容替换每个生成的流的效果.换句话说,由函数生成的所有单独的流被合并或"扁平化"为单个流.我们在这里想要的是类似的东西,但是我们想要将两级可选"压扁"为一个.
可选还支持flatMap方法.它的目的是将变换函数应用于Optional的值(就像map操作一样),然后将生成的两级Optional压缩为一个.
因此,为了使我们的代码正确,我们需要使用flatMap重写如下:
String version = computer.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
Run Code Online (Sandbox Code Playgroud)
第一个flatMap确保
Optional<Soundcard>返回an 而不是aOptional<Optional<Soundcard>>,第二个flatMap实现返回的相同目的Optional<USB>.请注意,第三个调用只需要是map(),因为getVersion()返回String而不是Optional对象.
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
Eug*_*ene 13
我不太确定我应该回答这个问题,但每当我遇到一个不理解这个问题的人时,我都会使用相同的例子.
想象一下,你有一个苹果.A map正在将该苹果转化apple-juice为例如或一对一的映射.
拿同样的苹果,只取出它的种子,即作为输入的一个苹果flatMap或一个或多个苹果,作为输出的许多种子.
小智 11
Map: - 此方法将一个Function作为参数,并返回一个新流,该流包含通过将传递的函数应用于流的所有元素而生成的结果.
让我们假设,我有一个整数值列表(1,2,3,4,5)和一个函数接口,其逻辑是传递的整数的平方.(e - > e*e).
List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> newList = intList.stream().map( e -> e * e ).collect(Collectors.toList());
System.out.println(newList);
Run Code Online (Sandbox Code Playgroud)
输出: -
[1, 4, 9, 16, 25]
Run Code Online (Sandbox Code Playgroud)
如您所见,输出是一个新流,其值是输入流的值的平方.
[1, 2, 3, 4, 5] -> apply e -> e * e -> [ 1*1, 2*2, 3*3, 4*4, 5*5 ] -> [1, 4, 9, 16, 25 ]
Run Code Online (Sandbox Code Playgroud)
http://codedestine.com/java-8-stream-map-method/
FlatMap: - 此方法将一个Function作为参数,此函数接受一个参数T作为输入参数,并返回一个参数R流作为返回值.当此函数应用于此流的每个元素时,它会生成一个新值流.然后将每个元素生成的这些新流的所有元素复制到新流中,该流将是此方法的返回值.
我们的图像,我有一个学生对象列表,每个学生可以选择多个科目.
List<Student> studentList = new ArrayList<Student>();
studentList.add(new Student("Robert","5st grade", Arrays.asList(new String[]{"history","math","geography"})));
studentList.add(new Student("Martin","8st grade", Arrays.asList(new String[]{"economics","biology"})));
studentList.add(new Student("Robert","9st grade", Arrays.asList(new String[]{"science","math"})));
Set<Student> courses = studentList.stream().flatMap( e -> e.getCourse().stream()).collect(Collectors.toSet());
System.out.println(courses);
Run Code Online (Sandbox Code Playgroud)
输出: -
[economics, biology, geography, science, history, math]
Run Code Online (Sandbox Code Playgroud)
如您所见,输出是一个新流,其值是输入流的每个元素返回的流的所有元素的集合.
[S1,S2,S3] - > [{"历史","数学","地理"},{"经济学","生物学"},{"科学","数学"}] - >采取独特的科目 - > [经济学,生物学,地理学,科学,历史,数学]
http://codedestine.com/java-8-stream-flatmap-method/
art*_*hur 11
map()和flatMap()
map()只需要一个函数一个lambda参数,其中T是元素,R是使用T构建的返回元素.最后,我们将得到一个带有类型R对象的Stream.一个简单的例子可以是:
Stream
.of(1,2,3,4,5)
.map(myInt -> "preFix_"+myInt)
.forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)
它只需要Type的第1到第5个元素Integer,使用每个元素从String带有值的类型构建一个新元素"prefix_"+integer_value并将其打印出来.
flatMap()知道flapMap()在F<T, R>哪里使用函数是有用的
T是一种可以从中构建Stream的类型.它可以是List(T.stream()),一个数组(Arrays.stream(someArray))等.来自Stream可以与/或形成的任何东西.在下面的例子中,每个开发人员都有很多语言,所以dev.语言是一个List,将使用lambda参数.
R是将使用T构建的结果Stream.知道我们有很多T实例,我们自然会有很多来自R的Streams.所有来自Type R的Streams 现在将被组合成一个来自Type R的单个'flat'流.
例
Bachiri Taoufiq的例子在 这里看到它的答案简单易懂.为了清楚起见,我们假设我们有一个开发团队:
dev_team = {dev_1,dev_2,dev_3}
Run Code Online (Sandbox Code Playgroud)
,每个开发人员都知道多种语言:
dev_1 = {lang_a,lang_b,lang_c},
dev_2 = {lang_d},
dev_2 = {lang_e,lang_f}
Run Code Online (Sandbox Code Playgroud)
在dev_team上应用 Stream.map()以获取每个开发人员的语言:
dev_team.map(dev -> dev.getLanguages())
Run Code Online (Sandbox Code Playgroud)
会给你这个结构:
{
{lang_a,lang_b,lang_c},
{lang_d},
{lang_e,lang_f}
}
Run Code Online (Sandbox Code Playgroud)
这基本上是一个List<List<Languages>> /Object[Languages[]].不是很漂亮,也不像Java8!
与Stream.flatMap()您可以"扁平化"的事情了,因为它需要上述结构
并将其转化为{lang_a, lang_b, lang_c, lang_d, lang_e, lang_f},基本能够用作List<Languages>/Language[]/ect...
所以你的代码结束会更有意义:
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();
Run Code Online (Sandbox Code Playgroud)
或者干脆:
dev_team
.stream() /* {dev_1,dev_2,dev_3} */
.flatMap(dev -> dev.getLanguages().stream()) /* {lang_a,...,lang_d, lang_e, lang_f} */
.doWhateverWithYourNewStreamHere();
Run Code Online (Sandbox Code Playgroud)
何时使用map()并使用flatMap():
使用map()时从信息流的类型T的每个元素应该被映射/变换为单一的类型R的结果元素的类型的映射(1个起始元件- > 1端部元件)和R型的元素的新的流退回.
使用flatMap()时从信息流的类型T的每个元素被认为映射/变换到类别的类型R的结果元件的是一种类型的映射(1点开始元素- >Ñ结束元素).然后将这些集合合并(或展平)到R类型的新元素流.这可用于表示嵌套循环.
前Java 8:
List<Foo> myFoos = new ArrayList<Foo>();
for(Foo foo: myFoos){
for(Bar bar: foo.getMyBars()){
System.out.println(bar.getMyName());
}
}
Run Code Online (Sandbox Code Playgroud)
发布Java 8
myFoos
.stream()
.flat(foo -> foo.getMyBars().stream())
.forEach(bar -> System.out.println(bar.getMyName()));
Run Code Online (Sandbox Code Playgroud)
Har*_*der 11
通过阅读所有消息,简单的理解方法是:
map如果您有flat元素列表,请使用:[0, 1, 2, 3, 4, 5]flatMap如果您有元素列表的列表,请使用:[[1, 3, 5], [2, 4, 6]]。这意味着,您的列表需要先展平,然后才能将映射操作应用于每个元素如果您将其视为map()迭代(一级for循环),flatmap()那么它就是两级迭代(如嵌套for循环)。(输入每个迭代的元素foo,然后foo.getBarList()在该元素中进行迭代barList)
map():获取一个流,对每个元素执行一些操作,收集每个过程的单个结果,输出另一个流。“做某事功能”的定义是隐含的。如果任何元素的处理导致null,null则用于组成最终流。因此,结果流中的元素数量将等于输入流的数量。
flatmap():采用元素/流的流和函数(显式定义),将函数应用于每个流的每个元素,并将所有中间结果流收集为更大的流(“扁平化”)。如果任何元素的处理结果为null,则将空流提供给“展平”的最后一步。如果输入是多个流,则结果流中的元素数量是所有输入中所有参与元素的总数。
简单的回答。
该map操作可以产生Stream一个Stream.EXStream<Stream<Integer>>
flatMap操作只会产生Stream一些东西。前任Stream<Integer>
| 归档时间: |
|
| 查看次数: |
314040 次 |
| 最近记录: |