在Java 8中,Stream.map()和Stream.flatMap()方法之间有什么区别?
当前回答
地图: 该方法以一个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);
输出:
[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] -> [{“历史”,“数学”,“地理”},{“经济学”、“生物学”},{“科学”,“数学”}]- >采取独特的主题- - - > [经济、生物、地理、科学、历史、数学]
http://codedestine.com/java-8-stream-flatmap-method/
其他回答
地图: 该方法以一个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);
输出:
[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] -> [{“历史”,“数学”,“地理”},{“经济学”、“生物学”},{“科学”,“数学”}]- >采取独特的主题- - - > [经济、生物、地理、科学、历史、数学]
http://codedestine.com/java-8-stream-flatmap-method/
简单的答案。
映射操作可以生成流的流。前流<流<整数> >
flatMap操作只会产生流。前流<整数>
Oracle关于Optional的文章强调了map和flatmap的区别:
String version = computer.map(Computer::getSoundcard)
.map(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
Unfortunately, this code doesn't compile. Why? The variable computer is of type Optional<Computer>, so it is perfectly correct to call the map method. However, getSoundcard() returns an object of type Optional. This means the result of the map operation is an object of type Optional<Optional<Soundcard>>. As a result, the call to getUSB() is invalid because the outermost Optional contains as its value another Optional, which of course doesn't support the getUSB() method. With streams, the flatMap method takes a function as an argument, which returns another stream. This function is applied to each element of a stream, which would result in a stream of streams. However, flatMap has the effect of replacing each generated stream by the contents of that stream. In other words, all the separate streams that are generated by the function get amalgamated or "flattened" into one single stream. What we want here is something similar, but we want to "flatten" a two-level Optional into one. Optional also supports a flatMap method. Its purpose is to apply the transformation function on the value of an Optional (just like the map operation does) and then flatten the resulting two-level Optional into a single one. So, to make our code correct, we need to rewrite it as follows using flatMap:
String version = computer.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
第一个flatMap确保返回Optional<Soundcard> 而不是一个Optional<Optional<Soundcard>>,和第二个flatMap 实现相同的目的,返回Optional<USB>。注意 第三个调用只需要一个map(),因为getVersion()返回一个 字符串而不是可选对象。
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
我有一种感觉,这里的大多数答案都把简单的问题复杂化了。如果你已经理解了地图是如何工作的,那就很容易掌握了。
在使用map()时,有些情况下我们可能会得到不需要的嵌套结构,flatMap()方法的设计是通过避免换行来克服这一问题。
例子:
1
List<List<Integer>> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3))
.collect(Collectors.toList());
我们可以使用flatMap来避免使用嵌套列表:
List<Integer> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3))
.flatMap(i -> i.stream())
.collect(Collectors.toList());
2
Optional<Optional<String>> result = Optional.of(42)
.map(id -> findById(id));
Optional<String> result = Optional.of(42)
.flatMap(id -> findById(id));
地点:
private Optional<String> findById(Integer id)
如果您认为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