map算子和flatMap算子

map和flatMap都是映射(转换),那么他们之间究竟有什么区别呢?

1.我们先简单了解下map算子:

 @org.junit.Test
 public void test1(){
	List<String> words = Arrays.asList("hello","world"); 
	words.stream()
	.map(String::length)  //使用了方法引用,将String类型转换为int类型
	.forEach(System.out::println);
 }
//输出:5   5

map是流的中间操作, Stream map(Function<? super T, ? extends R> mapper)

传入一个Function函数式接口,返回一个流。关于函数式接口和lambda表达式可以看我之前的随笔。


2.再看个例子,来简单了解下两者间的区别,先着重思考一下下面的案例用map会有什么问题?

​ 需求:传入一个集合 list = Arrays.asList(“hello”,”Hello”)

​ 要求:输出:h,e,l,o,H (单词里面的每一个字母去重 ,并且进行打印)

 @org.junit.Test
 public void test2(){  //错误演示
	 List<String> list = Arrays.asList("hello","Hello");//h,e,l,o,H 
	 list.stream()
	 .map(m->m.split(""))
	 .distinct()
	 .collect(toList())
	 .stream()
	 .forEach(System.out::println);	 
 }

那么输出结果符合我们的需求吗?

//输出结果:这俩行是个什么鬼?
[Ljava.lang.String;@51e2adc7
[Ljava.lang.String;@1a8a8f7c

这显然不符合我们的要求,那究竟是哪里出错了呢?我们一步一步分析一下:

1.Stream baseRDD = list.stream(); 将集合转换为流

2.Stream<String[]> mapRDD= baseRDD.map(w->w.split(“”)); 调用map算子,转换

3.Stream<String[]> distinctRDD= mapRDD.distinct(); 调用distinct算子,去重

4.List<String[]> collectRDD = distinctRDD.collect(toList()); 流转换为集合,最后输出

我们一步一步分析下来,看起来是不是还是没问题呢?接下来让我们再改写一下:

@org.junit.Test
public void test3(){

	List<String> words =  Arrays.asList("hello","Hello");//h,e,l,o,H 
	Stream<String[]> mapRDD =  words.stream()
	.map(word->word.split(""));
	mapRDD.map(Arrays::stream)
	.distinct()
	.collect(toList())
	.stream()
	.forEach(System.out::println);
	
}
//输出:这又是个什么鬼???是不是越来越迷糊了,不要着急
java.util.stream.ReferencePipeline$Head@2353b3e6
java.util.stream.ReferencePipeline$Head@631330c

再来一步一步分析一下:

Stream<String[]> map1RDD = words.stream().map(word->word.split(“”)); 转换

Stream<Stream> map2RDD = map1RDD.map(d->Arrays.stream(d));

Stream<Stream> distinctRDD = map2RDD.distinct();

List<Stream> finalList = distinctRDD.collect(toList());

这里我们需要注意的是:map转化(输入一个类型,返回另外一个类型)

​ 输入类型的值(值的类型是上一个数据集的泛型)

​ 输出数据的类型会作为下一个数据集的泛型

还是不理解?没关系,等会我们通过图来深刻理解一下。


那flatMap算子呢?

@org.junit.Test
public void test4(){
	List<String> words =  Arrays.asList("hello","Hello");//h,e,l,o,H 
	words.stream()
	.map(word->word.split(""))
	.flatMap(d->{
		      Stream<String> stream = Arrays.stream(d);
		return Arrays.stream(d);
	})
	.distinct()
	.forEach(System.out::println);
}
//输出
heloH

居然成功实现了需求,这两者究竟有什么区别呢?我们通过图画来更加生动形象的了解下(画图不易,值得一赞)

对比一下flatMap算子:

这样就一目了然了!!!


总结一下:

map算子:map返回值类型就是新的数据集的泛型

flatMap算子: flatMap算子返回类型就是新的数据集的类型


最后再看个案例:

​ 需求:输入:【1,2,3】【3,4】

​ 输出:【(1,3),(1,4),(2,3),(2,4),(3,3),(3,4)】

@org.junit.Test
public void test7(){
	//集合(.stream())
	List<Integer> number1 = Arrays.asList(1,2,3);
	List<Integer> number2 = Arrays.asList(4,5);
	/**
	 * 倒着推理一下 : 
	 *   最终的结果(终端): List<int[]>
	 *   终端操作的上一个操作:Stream<int[]>
	 *   
	 */
    List<int[]> pairs = number1.stream()
    .flatMap(i->{
//	    	 Stream<int[]> stream = 
//	    			 number2.stream().map(j->new int[]{i,j});
    	return number2.stream().map(j->new int[]{i,j});
    })
    .collect(toList());
    
    Stream<int[]> intArrayRDD =  pairs.stream();
    intArrayRDD.forEach(arr->{
    	for(int i : arr){
    		System.out.print(i+" ");
    	}
    	System.out.println();
    });
}//OK

至此,map算子和flatMap算子就介绍完毕了!


版权声明:本文为yZzcXQ原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/yZzcXQ/p/Stream-map-flatMap.html