在Java 8中,Stream.map()和Stream.flatMap()方法之间有什么区别?
当前回答
map和flatMap都可以应用于一个<T>的流,它们都返回一个<R>的流。不同之处在于map操作为每个输入值生成一个输出值,而flatMap操作为每个输入值生成任意数量(零个或多个)值。
这反映在每个操作的参数中。
map操作接受一个函数,该函数针对输入流中的每个值被调用,并产生一个结果值,该结果值被发送到输出流。
The flatMap operation takes a function that conceptually wants to consume one value and produce an arbitrary number of values. However, in Java, it's cumbersome for a method to return an arbitrary number of values, since methods can return only zero or one value. One could imagine an API where the mapper function for flatMap takes a value and returns an array or a List of values, which are then sent to the output. Given that this is the streams library, a particularly apt way to represent an arbitrary number of return values is for the mapper function itself to return a stream! The values from the stream returned by the mapper are drained from the stream and are passed to the output stream. The "clumps" of values returned by each call to the mapper function are not distinguished at all in the output stream, thus the output is said to have been "flattened."
典型的用法是flatMap的mapper函数返回Stream.empty(),如果它想发送零值,或者类似于Stream。(a, b, c)如果它想返回几个值。当然,任何流都可以返回。
其他回答
地图: 该方法以一个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,顾名思义,是映射和平面操作的组合。这意味着您首先将一个函数应用到元素上,然后将其压平。流。Map仅将函数应用于流,而不会将流平展。
为了理解流的扁平化是由什么组成的,考虑一个像[[1,2,3],[4,5,6],[7,8,9]]这样的结构,它有“两个层次”。扁平化意味着将其转换为“一级”结构:[1,2,3,4,5,6,7,8,9]。
我有一种感觉,这里的大多数答案都把简单的问题复杂化了。如果你已经理解了地图是如何工作的,那就很容易掌握了。
在使用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)
我想举两个例子来说明更实际的观点: 第一个使用地图的例子:
@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]。
推荐文章
- 在流中使用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