1. flatMap、map
集合使用flatMap和map来处理数据
val listStr01 = List("hello word", "hello hdfs", "hadoop hdfs")
//原版写法、flatMap扁平化
// val listStr02 = listStr01.flatMap((x:String) =>x.split(" "))
val listStr02 = listStr01.flatMap(_.split(" "))//简化版匿名函数 、按空格切割、将listStr01中三个元素切分成六个并放入新的list中
listStr02.foreach(println)
// 如何将list转换为map
println("---------------将list转换成map--------------")
val listToMap = listStr02.map((_, 1))//map就是映射 _就是数据,以数据当key 1就是固定的value
listToMap.foreach(println)
缺点:内存扩大了n倍、每一步计算内存都保留对象数据、 什么技术可以解决数据计算中间状态占用内存这一问题? iterator迭代器
2. 什么是迭代器、为什么会有迭代器模式
在集合中、因为迭代器迭代时是通过指针进行迭代的、如果多线程同时迭代一个集合的话 第一个迭代器迭代到指针3的时候 第二个迭代器来了、它迭代的话是从指针3开始迭代的、并不是从头开始迭代、它存放的只有指针
优化代码:
val it = listStr01.iterator //什么是迭代器、为什么会有迭代器模式、 迭代器里不存数据
// 集合中 因为迭代器迭代时是通过指针进行迭代的、如果多线程同时迭代一个集合的话 第一个迭代器迭代到指针3的时候 第二个迭代器来了、它迭代的话是从指针3开始迭代的、并不是从指针1开始迭代
val itStr02 = it.flatMap(_.split(" "))//简化版匿名函数 、按空格切割、将listStr01中三个元素切分成六个并放入新的list中
// itStr02.foreach(println)
// 如何将list转换为map
val itStr02tToMap = itStr02.map((_, 1))//map就是映射 _就是数据,以数据当key 1就是固定的value
itStr02tToMap.foreach(println) //这里不出现数据是因为上面 itStr02 遍历的时候将迭代器的指针跌倒到最后了、所以将上面foreach注释了就可以了
2.1 首先我们来看迭代器的源码
2.2 当咱们数据集进行迭代时、它首先会去new 一个抽象的迭代器、其中包含hashNext 和 next 方法,
//按照我的理解 StrictOptimizedLinearSeqOps.this 代表它自己、例:当前的那个数据集合
private[this] var current = StrictOptimizedLinearSeqOps.this
// 取反、如果当前无数据 会返回false
def hasNext = !current.isEmpty
// 它是将集合的首位、头部赋值给了r、然后将集合头部往后的数据重新赋给了current、返回一个r 如果是while循环的话 它会一直往后取、直到current.tail赋给current 为空的时候,走到def hasNext = !current.isEmpty 返回一个false 然后结束
def next() = { val r = current.head; current = current.tail; r }
2.3 接着咱们使用迭代器调用flatMap方法的时候 val itStr02 = it.flatMap(_.split(" "))
它还是会先new 一个抽象的迭代器、默认给cur置空、_hasNext默认设置为 -1 ,接着咱们看它flatMap的hasNext、和next方法
def hasNext: Boolean = {
//因为默认值给了-1
if (_hasNext == -1) {
//cur 取反 为true
while (!cur.hasNext) {
//self代表自己、意思说当前方法的迭代器、它问父迭代器有没有数据、咱们是通过it.flatMap(_.split(" "))调用的,如果父迭代器告诉他有数据那就取反为false不进行if后的操作
if (!self.hasNext) {
_hasNext = 0
// since we know we are exhausted, we can release cur for gc, and as well replace with
// static Iterator.empty which will support efficient subsequent `hasNext`/`next` calls
cur = Iterator.empty
return false
}
//父迭代器有数据将会调用这个方法
nextCur()
}
_hasNext = 1
true
} else _hasNext == 1
}
flatMap的nextCur方法:
private[this] def nextCur(): Unit = {
cur = null
//令cur 进行赋值、意思是从父迭代器中拿出了一条元素(hello word),传给我们的方法就是前面定义的split、然后将数组转换成迭代器付给了cur
cur = f(self.next()).iterator
_hasNext = -1
}
flatMap的next 方法
def next(): B = {
//这里的话它是看hasNext这个方法有没有值有的话不执行
if (hasNext) {
_hasNext = -1
}
//它会得到hasNaxt中split切割的数据、按照数据集来看就是 hello
cur.next()
}
这里最重要的就是cur,只要下游掉了hasNext 方法 cur为空 hasNaxt方法就会偷摸填充cur、下游只要掉next方法、next只会从cur中取元素返回给下游
2.3 咱们看 map方法、它也是new 一个抽象迭代器,它就负责掉父亲的hasNext和next方法和你的匿名函数
def map[B](f: A => B): Iterator[B] = new AbstractIterator[B] {
override def knownSize = self.knownSize
//调用父亲的hasNext
def hasNext = self.hasNext
//调用父亲的next
def next() = f(self.next())
}
2.4 什么时候开始执行这些迭代器呢?
//当咱们使用while循环用迭代器调用hasNext和next的时候方法才会执行
while (itStr02tToMap.hasNext) {
val tuple = itStr02tToMap.next()
println(tuple)
}
逻辑架构图: