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算子就介绍完毕了!


Java流中的map算子和flatMap算子的区别的更多相关文章

  1. Python 图像处理 OpenCV (12): Roberts 算子、 Prewitt 算子、 Sobel 算子和 Laplacian 算子边缘检测技术

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...

  2. Python 图像处理 OpenCV (13): Scharr 算子和 LOG 算子边缘检测技术

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...

  3. Java 8 中的抽象类和接口到底有啥区别?

    上一篇栈长发了这篇<Java 8 有多牛逼?打破一切你对接口的认知!>,帮助许多人解开了疑惑,还有读者留言说两者还有啥区别,故引发了此篇: 在我们面试时也会经常遇到面试官问抽象类和接口的区 ...

  4. Java集合中的Map接口

    jdk1.8.0_144 Map是Java三种集合中的一种位于java.util包中,Map作为一个接口存在定义了这种数据结构的一些基础操作,它的最终实现类有很多:HashMap.TreeMap.So ...

  5. Java集合中的Map接口怎么使用?

    Map(双列集合框架) 1.Map接口及实现类概述 Map 接口提供三种collection 视图,允许以键集.值集或键-值映射关系集的形式查看某个映射的内容.映射顺序 定义为迭代器在映射的 coll ...

  6. 解决 java循环中使用 Map时 在put值时value值被覆盖的问题

    其实很简单,只需要把容器换成list 然后在循环中,每次循环末尾map = new HashMap() 或者直接在循环中一开始就实例化hashmap(Map map = new HashMap();) ...

  7. java 泛型中 T 和 问号(通配符)的区别

    类型本来有:简单类型和复杂类型,引入泛型后把复杂类型分的更细了: 现在List<Object>, List<String>是两种不同的类型;且无继承关系: 泛型的好处如: 开始 ...

  8. Java虚拟机中的栈和堆的定义和区别

    在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配. 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配 ...

  9. 灰度图像--图像分割 Sobel算子,Prewitt算子和Scharr算子平滑能力比较

    学习DIP第47天 转载请标明本文出处:http://blog.csdn.net/tonyshengtan ,出于尊重文章作者的劳动,转载请标明出处!文章代码已托管,欢迎共同开发: https://g ...

随机推荐

  1. Problem 43 // Project Euler

    Sub-string divisibility The number, 1406357289, is a 0 to 9 pandigital number because it is made up ...

  2. App自动化测试方案

    App自动化测试方案 1.1  概述 什么是App自动化?为什么要做App自动化? App自动化是指给 Android或iOS上的软件应用程序做的自动化测试. 手工测试和自动化测试的对比如下: 手工测 ...

  3. Hi3518_SDK

    第一章 Hi3518_SDK_Vx.x.x.x版本升级操作说明 如果您是首次安装本SDK,请直接参看第2章. 第二章 首次安装SDK 1.Hi3518 SDK包位置 在"Hi3518_V10 ...

  4. android使用giflib加载gif

    转载请标明出处:https:////www.cnblogs.com/tangZH/p/12356915.html 背景不多说,反正ndk加载gif比java上加载gif好很多很多,主要体现在内存占用与 ...

  5. 大马提权详细过程webshell到提权

    .在shell路径这一栏里输入服务器端cmd.exe对应的绝对路径,这里用我们刚刚上传上去的smallchao.exe 8.WINDOWS常见命令:net user 查看所有用户query user ...

  6. 什么是Activiti

    什么是Activiti Activiti属于工作流引擎的一个开源实现.Activiti由Tom Bayen发起.在2010年5月发布了第一个版本.命名也很有意思的采取了Activities(活动)的化 ...

  7. VGG16等keras预训练权重文件的下载及本地存放

    VGG16等keras预训练权重文件的下载: https://github.com/fchollet/deep-learning-models/releases/ .h5文件本地存放目录: Linux ...

  8. Codeforces Round #295 (Div. 2) B. Two Buttons 520B

    B. Two Buttons time limit per test 2 seconds memory limit per test 256 megabytes input standard inpu ...

  9. python实验一

    安徽工程大学 Python程序设计实验报告 班级物流管理191 姓名彭艺    学号3190505139成绩          日期  2020年3月3日     指导老师    修宇 实验名称    ...

  10. 从String到==和hashcode

    public static void main(String[] args) { String s1 = "ni"; String s2 = "hao"; St ...