Java和Scala运行时都需要JRE,且Java和Scala都需要编译成字节码后才能在JVM上运行,实际工程中Scala一般会调用Java的API
var :变量值可改变
val :变量值不可改变
Object相当于java中的public static class修饰符(包含静态成员和方法),object不是对象,可以通过Object的apply方法控制对象的创建(单例模式,采用工厂模式)
抽象类的Object伴生对象中的apply()实际上是调用抽象类的子类构造方法创建,比如Graph.apply()实际上是调用了GraphImpl的构造方法
Any是Scala中所有基本类型的父类
AnyRef是Scala的所有引用类型的父类
Nil是Scala中空引用
函数背后实际是类和对象,在运行时Scala自动生成类,完全面向对象编程
1.Object.apply函数(工厂模式创建实例)
2.If(age>10){//条件块的返回值为if或者else的最后一行值
2
}
else{
1
}
val result=if(age>25) “Worker” else “Student” //if条件语句作为变量
3.标准输入输出函数
println()//输出
readLine()//输入
4.for
实际上是for(i<-array)//遍历array的每个元素
for(i<- 1 to 10){//循环10次
}
for(i<-0 until(array.length,step)){//从0到array.length-1,步长为step
}
5.break语句
val loop=new Breaks
loop.breakable{//可中断的语句块
}
6.函数定义Function
def func(参数名:参数类型):返回值类型{//默认最后一行即为返回值
}
定义默认参数的函数
def func(参数名:参数类型=默认值):返回值{
}
定义指定参数名称的函数
def func(i:Int,j:Int):Int{
}
val i=1
val j=2
func(j,i)
定义泛型输入参数
def func(i:Int*){
}
func(1,2,3,4,5)
val array=Array(1,2,3,4,5)
func(array:_*)//调用array(Range)每个元素
7.lazy延迟执行
只有当访问时才执行,类成员变量初始化延迟执行
lazy val i=10
I
8.异常处理
try{
监控块
}
catch{
case ex:IOExceptioon=>{
异常处理
}
case ex:FileNotFound=>{
异常处理
}
}
finally{
善后
}
9.Array和ArrayBuffer
val array=Array(1,2,3,4,5)
val buffer=ArrayBuffer(1,2,3,4,5)
buffer+=(7,8,9,0)
buffer.insert(offset,elem)//在指定offset之后插入elem
buffer.remove(offset,num)//在指定offset之后删除num个元素
Sorting.quicksort(buffer.toArray)//快速排序
10.yield字段
val array2=for(i <- array) yield i*i
yield 关键字的简短总结:
Ø 针对每一次 for 循环的迭代, yield 会产生一个值,被循环记录下来 (内部实现上,像是一个缓冲区).
Ø 当循环结束后, 会返回所有 yield 的值组成的集合.
Ø 返回集合的类型与被遍历的集合类型是一致的.
11.filter函数
array.filter(_%3==0).map(i=>i*i)//array中3的倍数翻倍
12.Map集合类
val map=Map(“key”->value)//Map不可变,当发生改变时则会生成新的map,getOrElse(key,default)如果有key则返回value否则返回default
val map=new HashMap[String,Int] //创建HashMap实例
val linked=new LinkedHashMap[String,Int]//记录插入的顺序
Val sorted=new SortedMap[String,Int]//sorted中元素按照key字典排序
map+=(“Scala”->12,”Java”->20)//添加元素
map-=(“Scala”) //删除元素
for(key<-map.keySet){//valueSet
println(key)
}
for((key,value)<-map){
println(key+”:”+value)
}
val tuple=Tuple(“asas”,123,”dada”,”dasfa”)
tuple._1 //访问tuple中的第一个元素
val (elem1,elem2)=func();//tuple作为返回值
13.面向对象编程
class Scala{
var name=”spark”
def sayName(){
println(name)
}
}
var scala=new Scala
scala.name//等价于getName()
scala.name_=(“caiqi”)//等价于setName(“caiqi”)
//安全性考虑
private[this] var myName=”spark” //更严格
def name=this.myName//自定义get()
def update(newName:String) {//自定义set()
myName=newName
}
def this(name:String){//自定义构造器
this()//默认构造器能初始化各种成员变量
myName=name
}
class Person(age:Int,name:String){
var myAge=age
var myName=name
var mySex=”nan”
def this(age:Int,name:String,sex:String){//自定义构造方法
this(age,name)//默认构造方法
this.mySex=sex
}
def name=myName//自定义getter方法
def sex=mySex
def age=myAge
def updateName(newName:String){//自定义setter方法
this.myName=newName
}
def updateSex(newSex:String){
this.mySex=newSex
}
def updateAge(newAge:String){
this.myAge=snewAge
}
}
内部类Parent和Child,每一个child都有属于自己的parent实例
14.Object伴生对象
object Person{//允许定义一些静态成员或者方法
private var temp=”1”//静态成员
def playName(){//静态方法
}
}
Object第一次调用时会调用默认无参的构造器,然后初始化静态字段(只会调用一次),可以放一些全局唯一的常量和类公用方法
***Object中的apply方法采用工厂模式创建对象
abstract class 中有抽象方法,继承abstract class需要实现抽象方法,且允许override覆盖父类方法(非final),子类使用父类同名方法可用super,抽象属性(即属性没初始化),允许单继承abstract class,而trait(通用功能,工具类)允许多继承with连接
Object伴生对象与Class伴生类之间可以相互调用
@transient 非序列化字段,常用于临时保存数据或者易于重新计算的数据
15.函数式编程
1)def func(name:String):Unit{println(“caiqi”)}//定义函数
val func1=func _//定义函数变量func1,调用时和func相同
2) 匿名函数
val func=(name:String)=>{println(name)}//定义匿名函数,func(“caiqi”)调用
3)函数参数
def hello(name:String){println(name)}
def func(func1:String=>Unit,name:String):Unit={func1(name)}
func(hello,”george”) //调用func函数,以函数为参数
4)map函数
val array=Array(1,2,3,4)
array.map(item=>{
println(item)
})
5)函数作为返回值
def func_returned(content:String)=(name:String)=>println(content+”:”+”name”)
val result=func_returned(“caiqi”) //返回值result是一个函数
result(“xinghai”)//调用返回值
6)如果函数的函数体内只使用一次函数的参数,则在函数体内使用该参数时可以用_代替
7)闭包:函数变量超过其作用域但还是可以访问(实际上是scala生成了个对象保存该函数变量)
8)函数的柯里化
def func(x:Int)=(y:Int)=>x+y
func(1)(2)//可直接调用
def func(x:Int)(y:Int)=x+y//变形
9)reduceLeft函数,flatMap函数
(1 to 100).reduceLeft(_+_)//每个元素从左至右相加
Val list=List(“dada ada ada”,”wqwe wqdq fsfs”)
list.flatMap(_.split(“ ”))
10)zip函数
val list=List(“caiqi”,”george”,”xinghai”)
list.zip(List(10,6,4))//结果为List(String,Int)
16.模式匹配
1)类似于switch case
def func(str:String):Unit={
str match{
case “data” => {处理逻辑}
case tmp if tmp==”flink” => {处理逻辑}
case _ => {如果都匹配不到的处理逻辑}
}
}
2)try catch语句段
try{
监视块
}
catch{
case ex: FileNotFoundException => {处理逻辑}
}
3)Array数组匹配
def data(array:Array):Unit={
array match{
case Array(“demo”) => println(“demo”)
case Array(spark,hadoop.flink) => println(spark +”:”+hadoop+ “:’+flink) //模式匹配Array中每个元素,分别用变量表示
case Array(“spark”,_*) => println(“spark”)
case _ =>{否则处理逻辑}
}
}
4)case class
case class Person(id:Int,name:String,age:Int) //定义case class相当于java bean
case class Student(id:Int,name:String,age:Int) extends Person
case class Teacher(id:Int,name:String,age:Int) extends Person
def func(person:Person):Unit={
person match{
case Student(id,name,age) => {对student的处理逻辑}
case Teacher(id,name,age) => {对teacher的处理逻辑}
}
}
val student=new Student(1,”caiqi”,23)
val teacher=new Teacher(2,”xinghai”,22)
func(student)//相当于Scala自动生成了Student的伴生对象然后通过调用apply方法创建实例
func(teacher)
5)Some 和 None
X match{//x是Option对象
case Some(t) =>{有值对t处理}
case None=> {无值处理}
}
6)匹配值 case value
7)匹配类型 case type:Type
17.隐式转换
隐式转换可以通过import导入上下文或者调用Object伴生对象中的隐式函数
1)隐式转换函数放在object中
class Sport{
val name=”caiqi”
}
object Sport{
implicit def sport2ball(sport:Sport):Ball={
new Ball(sport.name)
}
}
class Ball(name:String){
def play():Unit={
println(“playing ball”)
}
}
val sport=new Sport
sport.play()//隐式转换,本来sport中不存在play(),因此scala编译器会从其上下文或者object伴生对象中寻找合适的隐式转换得到目标对象,然后调用目标对象的方法
2)隐式转换参数
implicit val level=new Level //隐式参数声明
def test(name:String)(implicit level:Level):Unit={
}
test(“spark”)
3)隐式对象
implicit object StringAdd extends SubTemplate[String]{ //定义隐式对象StringAdd
override def add(x:String,y:String)=x concat y
}
implicit object IntAdd extends SubTemplate[Int]{//定义隐式对象IntAdd
override def add(x:Int,y:Int)=x+y
}
def sum[T](xs:List[T])(implicit m:SubTemplate[T]):T={
m.add(xs.head,sum(xs.tail))
}
println(sum(List(1,2,3,4,5)))//调用隐式对象
4)隐式类型
implicit class FileEnhance(file:File){ //定义隐式类
def read=Source.fromFile(file.getPath).mkString
}
implicit class OP(x:Int){
def addSAP(y:Int)=x+y
}
1.addSAP(2) //相当于首先根据隐式类型创建op对象 val op=new OP(1) op.addSAP(2)
Scala寻找位置隐式类的顺序是:
1)当前类的伴生对象中
2)可以把所有的隐式类写入一个Object中,然后使用时import到上下文
18.异步并发模型Actor(Spark 源码Master send(message)/Worker.receive() case 模式匹配 sendToMaster发送反馈)Driver中的并发编程DAGScheduler->DAGSchedulerEventProcessLoop->LinkedBlockingDeque->Thread.run()线程不断take()从队列中取event,onReceive(event)->doOnReceive(event) case event模式匹配事件并处理
1)创建并启动Actor
class ActorA extends Actor{
def act(){
loop{
react{//react支持共享线程
case x:Int => println(x)
}
}
}
}
object ActorTest{
def main(args:Array[String]){
val actorA = new ActorA//创建ActorA实例
actorA.start()//启动actorA
actorA ! (1) //给actorA发送消息
}
}
2)与其他Actor通信
class ActorB extends Actor{
def act(){
loop{
react{
case (x:Int,y:Int,actor:Actor) => actor ! (x+y) //给actor发送x+y的结果
}
}
}
}
object ActorTest2{
def main(args:Array[String]){
val actorA=new ActorA
val actorB=new ActorB
actorA.start()
actorB.start()
actorB ! (1,2,actorA) //首先给actorB传信息,然后actorA打印出3
}
}
3)同步消息(!?)容易产生死锁尽量避免使用
actorA !? (1) //以同步方式发送1,只有收到结果才会发送下条信息
4)Future(!!)
val future=actorA !! (1) //延迟通信
future() //开始通信
5)Actor相互监控(link方法关联多个Actor)
19.类型系统
1)泛型类和泛型函数
class Temp[T](name:T){
def func(name:T):Unit={处理逻辑}
}
2)上边界和下边界
_ <: Class 则表示_肯定是Class的类型或者子类型(上边界)
_>: Class 则表示_肯定是Class的超类或者接口(下边界)
new Club(p1,p2).communicate
3)Ordering[T]
class Compare[T:Ordering](val x:T.val y:T){
def bigger(implicit ordered:Ordering[T])=if(ordered.compare(x,y)>0)x else y
}
val compare=new Compare(1,2)
compare.bigger
4)逆变和协变
class Person[+T] //协变即如果A是B的子类,则Person[A]是Person[B]的子类
class Person[-T] //逆变则相反
class Meeting[+T] //协变,def participateMeeting指定meeting是Meeting[Engineer]类型,由于Expert是Engineer的子类,因此在实际调用时participateMeeting(new Meeting[Expert])
Seq[Dependence[_]]等价于Seq[Dependence[T]]
5)Type
type m=String //通过type引用类型
this.type://使用this对象的类型
Self.type://同上
6)Scala依赖注入
trait S1{//定义接口
def h():Unit
def fun(str:String)=println(“hello”+str)
}
class S2{self:S1=>
def g(str:String) = fun(str)
}
val aa=new S2() with S1
T:ClassTag指运行时的类型(在编译时类型信息不够)
View bounds(<%)
def method[A<%B] //A是B的隐式转换类型(A=>B)
class Dog(val name:String)//val关键字说明name是一个成员变量
val dog=new Dog(“xinghai”)
dog.name//访问成员变量name
20.Spark快速启动的原因:粗粒度即初始化的时候就分配好资源,提交任务并资源复用
21.Spark快速计算的原因:基于内存计算(迭代计算直接从内存中取数据,避免I/O开销);DAG执行引擎(Job->Stages->RDDs->Partitions->Tasks)
22.Spark SQL可以取代Hive的执行引擎
23.Spark弹性计算的体现:
1)自动在内存和磁盘数据存储之间切换
2)基于血统的高效容错
3)Task失败会进行特定次数的重试(默认是4次)
4)Stage失败会进行特定次数的重试,只计算失败的分片(默认是3次)
5)Checkpoint会启动新的Job将数据写入磁盘,持久化Persist
6)数据分片Partition粒度可调(比如内存紧张时,切分大的Partition;合并小的Partition提高效率)
def coalesce(numPartitions:Int,shuffle:Boolean=false)(implicit ord:Ordering[T]=null) //自动分区,小数量Partition->大数量Partition可能需要shuffle即shuffle=true
7)数据调度弹性:DAG,Task均与资源管理器无关,先分配资源后执行Task
24.Spark耗时的四种场景
1)缓存耗时
2)计算链条过长(血统过长)
3)Checkpoint持久化
4)Shuffle操作
21.Scala继承
Scala继承能复用代码,Scala类继承时不能继承其伴生对象,RDD的抽象方法compute()和getPartitions()
RDD默认构造器(Primary Constructor,实例化初始状态,初始化成员,初始化动作)需要传入sparkContext和Dependencies,后面的def 方法中可直接使用,自定义构造器中必须包含Primary Constructor,都会实例化对象,
isInstanceOf(obj isInstanceOf(Object))//判断obj是否是Object的实例
asInstanceOf (obj asInstanceOf(Object))//obj转换为Object
obj.getClass()//获得obj运行时的类型
classof[T]//T类型
22.面向接口编程
1)Trait既可以包含抽象方法又可以包含已实现方法(工具类),with连接多接口Trait
2)抽象属性:
val name:String //val 变量必须指定变量的类型,则称为抽象属性
3)对象混入接口
可以随时扩展第三方实现,RichLogger就是混入的接口
23.Scala集合类
RDD本身是一个集合,RDD.getPartitions()返回Array[Partition],每个Partition本身又是由多条记录组成,RDD.getDependencies()返回Seq[Dependency]
1)集合类必须继承Iterable的Trait
2)Array是一个基础的数据结构
val array=new Array[Int](5)//创建Array
val array=Array(1,2,3,4,5)//创建Array
array(2)=1 //Array元素赋值
val arrayBuffer=ArrayBuffer[Int]()
arrayBuffer+=1 //往ArrayBuffer中添加元素
arrayBuffer+=(2,3,4,5) //往ArrayBuffer中添加元素块
arrayBuffer++= Array(1,2,3,4,5) //往ArrayBuffer中添加数组
arrayBuffer.insert(offset,elem)//在下标offset前插入元素elem
arrayBuffer.remove(offset)//删除offset位置元素
arrayBuffer.toArray//arrayBuffer -> array
array.mkString(“,”) //数组array中每个元素以,分割并构成字符串
3)Scala分为可变的集合(scala.collection.mutable)和不可变集合之分(scala.collection.immutable)
4)List属于不可变集合
val list=List(1,2,3,4,5)
list.head()//第一个元素
list.tail()//除了第一个元素外的其他元素组成新的列表
list::0//拼接新的元素,构建新的列表
list为空的话,返回Nil
5)LinkedList
val linkedList=LinkedList(1,2,3,4,5)
while(linkedList!=Nil){//遍历LinkedList元素
println(linkedList.elem)//打印第一个元素
linkedList=linkedList.tail
}
linkedList.+:(2) //追加元素
6)Set不可重复的元素集合,元素是无序的
val set=Set(1,2,3,4,5)
set=set+1 //添加元素
7)LinkedHashSet 不可重复的元素集合,元素是有序的(和插入顺序一致)
val linkedHashSet=LinkedHashSet(1,2,3,5)
linkedHashSet+=4
8)SortedSet 有序的不可重复元素集合
val sortedSet=SortedSet(1,2,3,4,5,8,7) //会进行排序
24.Scala偏函数
偏函数 PartialFunction(Scala中函数即类)
val isEven:PartialFunction[Int,Unit]={
case x:Int if(x%2==0) => x+”is odd”
}
val evenNumbers=sample.collect(isEven)
evenNumber.foreach(println)
val numbers=sample map (isEven orElse isOdd)
工作原理:偏函数传入参数->apply(),apply()的执行体即是偏函数的body(一般用作模式匹配)
25.Scala包管理
import java.awt._ // 引入包内所有成员
import java.awt.{Color, Font}//允许使用awt包中的Color,Font类
import java.util.{HashMap=>JavaHashMap} //将Java中的HashMap重命名
import java.util.{HashMap=>_}//隐藏java.util.HashMap,避免命名冲突
import java.util.{HashMap => _, _} // 引入了util包的所有成员,但是HashMap被隐藏了
private[awt] //包限制,只能在awt包下才能使用,如果某个应用程序需要使用此类,则该应用程序必须也在awt下
26.继承覆写
class Person{
val name:String=”xca”
def func(name:String){
println(name+”person”)
}
}
class Student extends Person{
override val name:String=”caiqi” //覆写成员变量
override def func(name:String){ //覆写成员函数
println(name+”student”)
}
}
27.Any,AnyRef
Any类似于Java中的Object,即是所有的基类,可实现所有的接口方法(equals,hashCode)
28.Scala提取器和注解
1)注解
@volatile 多线程并发控制,多线程操作全局变量的过程,首先会将全局变量拷贝到本地线程,执行完成后更新全局变量,每次获取该值时强制刷新以获取最新值
@deprecated 被废弃的接口,有可能在大的版本更新中删除
@developerApi 框架开发使用的 API
@Experimental 实验测试功能
@transient 不参与序列化和反序列化,只存在本进程
2)提取器
val person=Person.apply(“Spark”,6) //通过Object的apply()创建实例person
val Person(name,age)=person //调用Object的unapply()提取person的name和age并赋值
自定义提取器unapply()
29.文件和XML操作
Executor->TaskRunner->序列化和反序列化
@SerialVersionUID(99L) class DTSpark(val name:String) extends Serialize
def serialize[T](o:T):Array[Bytes]={//输入待序列化对象,输出字节数组
//val bos=new ByteArrayOutputStream()//网络序列化
val bos=new FileOutputStream(“/usr/local/text.txt”)//磁盘序列化
val oos=new ObjectOutputStream(bos)
oos.writeObject(o)
oos.close()
bos.toByteArray //输出字节数组
}
def deserialize[T](bytes:Array[Byte]):T={//输入字节数组,输出反序列化对象
//val bis=new ByteArrayInputStream(bytes)
val bos=new FileInputStream(“/usr/local/text.txt”)//磁盘序列化
val ois=new ObjectInputStream(bis)
ois.readObject.asInstanceof[T]
}
Scala天然对XML支持
val person=<person id=”bigdata”><name>caiqi</name></person> //scala.xml.Elem
person.atrribute(“id”).get //获得person的属性值
val people=<person id={person(0)}>{person(1)}</person>
val file=XML.loadFile(“/usr/local/pom.xml”) //加载XML文件
file.label //pom.xml标签
file.child //子元素
file.attribute //属性
Source.fromFile(“/usr/local/test.txt”,”UTF-8”) //读取文件
Source.fromURL(“http://spark.apache.org/”,”UTF-8”) //读取网页
(1 to 5).foldLeft(10)(_-_) //-5
10:1
9:2
7:3
4:4
0:5
(1 to 5).foldRight(10)(_-_) //-7
5:10
4:-5
3:9
2:-6
1:8
30.Scala外部命令和正则表达式
import sys.process._
“javac Hello.java” !
Scala外部命令工作原理:Scala运行在JVM上,JVM可以直接与OS交互
val elem=[a-z].r //scala.util.matching.Regex +1个或者多个字母 *0个或者多个字母
elem.findFirstIn(“Spark is cool”) //找到第一个符合正则表达式的元素
elem.findAllIn(“Spark is cool”) //找到所有符合正则表达式的元素
Elem.replaceAllIn(“Spark is cool”,”123”)//所有符合正则表达式的元素都替换成123
31.继承与Trait进阶
Scala是一个彻底面向对象的语言
Any :Scala中所有类的父类包括equals,isInstanceOf,asInstanceOf,hashCode等接口方法
AnyRef(定义所有接口,抽象类,自定义类类似于Java中的Object):Scala中所有引用类的父类包括,天生对线程有支持(wait,notify等)
AnyVal(基本类型Double ,Int的父类)
Any->AnyRef(自定义类)/AnyVal(基本类型)
Nothing和Null是所有继承的最低端,LNil等同于List[Nothing]
Scala函数的实质是类
val func=(x:Int)=>x+1 //匿名函数func
val func=new Function1[Int,Int]{
def apply(x:Int):Int=x+1
}
Trait中如果全是抽象方法,则实质上是Java中的Interface和抽象方法
Trait中如果全是实现方法,则实质上是Java中的abstract class且方法都是static
32.Scala Actor异步并发模型
Actor实际上就是一条线程
receive://没有线程复用,每次都会创建一个线程,消耗资源且效率低
react//:线程复用
Executor=Netty+ThreadPool
33.Scala核心力量
基于自上而下(对象,面向对象编程,软件系统可作为一个个对象,具体功能由对象本身以及对象之间通信完成)和自下而上(动作,函数式编程,强调功能的具体实现)的软件设计和编程实践的基础之上结合数据状态不可变性(简化编程,提升效率,减少Bug,方便分布式并发)基础之上的融合了类型系统()和隐式转换的函数式编程
34.Scala黄金定律
1)数据状态不可变
2)优先考虑面向值的编程方式
3)多步操作时采用this.type执行链式操作
4)使用Option(None/Some),用None解决Null,Option可直接调用map等算子操作
5)使用伴生对象的apply工厂方法构造类或者抽象类的实例对象
35.Scala面向对象内幕实战解密
object HelloFileOpps extends App{//相当于继承了App的main方法,args来自于App的main方法,Trait App extends DelayedInit(延迟初始化){
private val initCode=new ListBuffer[() => Unit]
override def delayedInit(body:=>Unit){
initCode+=(()=>body) //将HelloFileOpps中的body(Body的Object.apply创建body)迁移到App的main方法中,body保存在App的initCode中
}
}
}
36.隐式转换实质
Import Student._ //实际上会导入Class Student和Object Student的所有成员
隐式转换转换作用域:
本地>>Object伴生对象中的隐式成员>import Student.content(具体导入)>import Student._(模糊导入)