Stream.map()
和Stream.flatMap()
方法有什么区别?Oracle在Optional文章中强调了map和flatmap之间的差异:
String version = computer.map(Computer::getSoundcard)
.map(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
String version = computer.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
Optional
指针的方法,如果getter
返回Optional
,那么现在就不会抛出NullPointerException
了。 - Mike我不太确定是否应该回答这个问题,但每当我遇到不理解的人时,我都会使用同样的例子。
想象一下你有一个苹果。一个map
就像是将这个苹果变成例如apple-juice
或者是一个一对一映射。
取同一个苹果,只取出里面的种子,这就是flatMap
的作用,或者是一个一对多,一个苹果作为输入,多个种子作为输出。
flatMap
的情况,您是先将每个苹果的种子收集到单独的袋子中(一个苹果对应一个袋子),然后再将所有的袋子倒入单个袋子中吗? - Derek Maharflatmap
并不是真正的惰性求值,但自从 Java 10 以后,它就变得惰性了。 - EugeneMap方法:该方法接受一个函数作为参数,并返回一个新的流,其中包含将传递的函数应用于流所有元素生成的结果。
假设我有一个整数值列表(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);
输出:-
[1, 4, 9, 16, 25]
[1, 2, 3, 4, 5] -> apply e -> e * e -> [ 1*1, 2*2, 3*3, 4*4, 5*5 ] -> [1, 4, 9, 16, 25 ]
http://codedestine.com/java-8-stream-map-method/
FlatMap :- 该方法接受一个函数作为参数,这个函数以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);
输出:-
[economics, biology, geography, science, history, math]
如你所见,一个输出是一个新的流,其值是由输入流的每个元素返回的流中所有元素的集合。
[ S1 , S2 , S3 ] -> [ {"历史","数学","地理"}, {"经济学","生物学"}, {"科学","数学"} ] -> 取唯一的科目 -> [经济学, 生物学, 地理, 科学, 历史, 数学]
通过阅读所有消息,简单的理解方式是:
map
flatMap
。这意味着,在对每个元素应用 map 操作之前,需要将您的列表扁平化map()
视为迭代(单层循环),则flatmap()
是双层迭代(嵌套循环)。输入每个迭代的元素foo
,执行foo.getBarList()
并再次在barList
中迭代。
map()
:获取流,对每个元素进行操作,收集每个过程的单一结果,输出另一个流。 "do something function"的定义是隐含的。如果任何元素的处理结果为null
,则使用null
来组成最终流。因此,结果流中的元素数将等于输入流的数量。
flatmap()
:获取元素/流的流和一个函数(明确定义),将该函数应用于每个流的每个元素,并收集所有中间结果流以形成更大的流(“扁平化”)。如果任何元素的处理结果为null
,则空流将提供给“扁平化”的最终步骤。如果输入是几个流,则结果流中的元素数是所有参与元素的总和。简单回答。
map
操作可以生成一个Stream
的Stream
。例如:Stream<Stream<Integer>>
flatMap
操作将只生成某种类型的Stream
。例如:Stream<Integer>
这些Stream API方法的定义:
map(Function mapper)是一种中间操作,它返回一个流,该流由将给定函数应用于此流的元素的结果组成。
flatMap(Function mapper)是一种中间操作,它返回一个流,该流由将此流的每个元素替换为通过将提供的映射函数应用于每个元素而生成的映射流的内容组成。简而言之,它用于将Stream of Stream转换为值列表。
看一个例子:
List<String> myList = Stream.of("Apple", "Orange")
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(myList);
它会打印:[APPLE, ORANGE]
我们可以将map()
更改为flatMap()
吗?
List<String> myListFlat = Stream.of("Apple", "Orange")
.flatMap(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(myListFlat);
不好意思,我们现在能看到一个错误:
java: incompatible types: cannot infer type-variable(s) R
(argument mismatch; bad return type in method reference
java.lang.String cannot be converted to java.util.stream.Stream<? extends R>)
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
flatMap()
方法期望返回一个流的函数。在第二个示例中,我将一个方法引用传递给String.toUpperCase()
,它返回一个字符串。因此,我试图在字符流而不是字符串流上应用flatMap()
。flatMap()
的用途了。
让我们构建一个列表的列表:List<List<String>> list = Arrays.asList(
Arrays.asList("Apple"),
Arrays.asList("Orange"));
System.out.println(list);
并且它会打印出: [[Apple], [Orange]]
。如果我们想要将它展平,让我们使用 flatMap()
:
List<String> flattedList = list
.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
System.out.println(flattedList);
现在它会打印:[苹果,橙子]
Sources: https://www.geeksforgeeks.org/stream-flatmap-java-examples/
流操作flatMap
和map
接受一个函数作为输入。
flatMap
期望函数返回每个流的新流,并返回由函数返回的每个元素的流组合而成的流。换句话说,使用flatMap
,对于源中的每个元素,函数将创建多个元素。http://www.zoftino.com/java-stream-examples#flatmap-operation
map
期望函数返回转换后的值,并返回包含转换元素的新流。换句话说,使用map
,对于源中的每个元素,函数将创建一个转换元素。http://www.zoftino.com/java-stream-examples#map-operation
map
为列表中的每个条目发出一个项,而flatMap
基本上是一个map
+flatten
操作。更明确地说,当您需要多个值时,请使用flatMap,例如当您期望循环返回数组时,在这种情况下,flatMap将非常有用。
我已经写了一篇关于此的博客,您可以在这里查看。
map :: Stream T -> (T -> R) -> Stream R
,flatMap :: Stream T -> (T -> Stream R) -> Stream R
。 - Chris Martin<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
。 - Stuart Marksmap
方法的映射函数返回类型为R
,而flatMap
方法的映射函数返回类型为Stream<R>
。flatMap
方法返回的流是将所有映射后的Stream<R>
连接起来的结果。两种方法都返回类型为Stream<R>
的流,区别在于映射函数的返回值类型,一个是R
,一个是Stream<R>
。 - derekmmap
。如果每个元素将被转换为多个值,并且需要展平结果流,则使用flatMap
。 - DimaSan