在Java 8中,Stream.map()和Stream.flatMap()方法之间有什么区别?


当前回答

我不太确定我是否应该回答这个问题,但每当我面对不理解这一点的人时,我就用同样的例子。

假设你有一个苹果。例如,地图是将苹果转换为苹果汁或一对一映射。

同样的苹果,只得到种子,这就是flatMap所做的,或者一对多,一个苹果作为输入,许多种子作为输出。

其他回答

一行回答: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]

代码使用:

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);
  }
}

流操作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,我们有一个元素列表和一个(函数,动作)f,这样:

[a,b,c] f(x) => [f(a),f(b),f(c)]

对于平面映射,我们有一个元素列表,我们有一个(function,action) f,我们希望结果是扁平的:

[[a,b],[c,d,e]] f(x) =>[f(a),f(b),f(c),f(d),f(e)]

流。flatMap,顾名思义,是映射和平面操作的组合。这意味着您首先将一个函数应用到元素上,然后将其压平。流。Map仅将函数应用于流,而不会将流平展。

为了理解流的扁平化是由什么组成的,考虑一个像[[1,2,3],[4,5,6],[7,8,9]]这样的结构,它有“两个层次”。扁平化意味着将其转换为“一级”结构:[1,2,3,4,5,6,7,8,9]。

.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]。