scala定义:
面向对象与函数式编程。
安装:
window 使用msi 直接安装,会默认修改环境变量
mac 安装需要将解压包 ,解压移动改名到/Users/zhugaopeng/scala 下(因为idea需要找到安装地址),配置环境变量 ~/.bash_profile 配置完后需要source一下 里配置SCALA_HOME,如下:
SCALA_HOME=/Users/zhugaopeng/scala
PATH="/Library/Frameworks/Python.framework/Versions/2.7/bin:${PATH}"
export PATH=$PATH:$SCALA_HOME/bin
scala 文件格式:
object 静态类,trait 相当于接口(但是可以实现方法),class类。启动main方法写在object里,也可以用object类继承app,也是入口。
Scala语法
val 引用不可变 相当于java中final修饰
var 引用可变
Scala中只有7种数值类型:Byte,Char,Int,Long,Float,Double,Boolean 都没有包装类型
判断if(x>0)1 else ()
如果else不写也可以,()是代表false返回(),这是unit类型,相当于java中的void
返回的类型可以不同
for循环 for(i <- 表达式/数组/集合)
1 to 10 是1,。。。10
1 until 10 是1.。。。9
还可以嵌套和加条件
for( i <- 1 to 3 ; j <- 1 to 3 if i != j) print(i)
使用yield 返回 val x = for(i <- 1 to 10) yield i 这是将1到10封装到x中形成vector集合
map方法: 也是将变量循环 arr.map(_*10) 即循环将arr中元素*10,其中map中需要放函数
定义方法:def m1(x:Int,y:Int):Int=x*y
必需的是 =》定义方法关键字def,方法名m1 ,参数,方法体。
不必需的是返回类型,编译器会自动推断出,++但是在递归方法中,必需指定返回类型++
定义函数:val f1 = (x:Int,y:Int) => x+y 或者val f2: (Int,Int) => Int ={(x,y)=>x*y}
f1 中 中间是参数类型,最后是方法体
f2 中 前面是参数类型,后面是返回类型,最后是方法体
方法体中传函数
def m1(f:Int=>Int):Int={
f(3)
}
这个中,f是函数,f的参数是int类型,返回值是int类型
匿名函数:也就是前面不加名字
方法转换成函数
在Scala语言中,所有运算符都是方法
方法后面空格下划线如: m1 _
在map(方法) 中 方法会隐式到转换成函数
foreach也是遍历到方法像:arr.foreach()
mutable 变长类
immutable 定长类 初始化后就不可变
ArrayBuffer 追加元素
+=1 或者+=(1,2,3)或者append 追加元素
++=arr或者++=arrbuffer 追加数组
insert 插入数组
remove(下标,几个元素)删除几个元素
val arr=Array(1,2,3,4,5,6)
val res=for(i<- arr;if(i%2==0)) yeild i*10 //偶数*10
val res =arr.filter(_%2==0) //偶数取出
val res =arr.filter(_%2==0).map(_*10) //偶数*10
arr.sum 求和
arr.max arr.min
arr.sorted 排序升序
arr.reverse 反转
arr.sortWith(_>_) 降序
arr.sortWith(_<_) 升序
映射 也就是hashmap
声明方式:
val map1=Map("tt"->24,"aa"->18,"bb"->19)
val map2=Map(("tt",24),("aa",18),("bb",19))
map1.getOrElse("tt",0) //如果获取不到值返回0
//如果导到是可变包下面到类,映射val是可变的,因为val是指向引用
元组:用小括号包裹的一个或多个值,类型可以不同
val t=(1,"S",true,3.14)
t._1 //通过。下划线取第几个值(从1开始)
val t2,(x,y,z)=(111,222,333)//如果一一对应可以通过像x,y,z来获取相应位置的值
val arr1=Array(("a",1),("b",2)
arr1.toMap//数组转映射
拉链操作
//两个数组 生成 元祖的集合,多余的数自动删除 以短的为标准
val arr1=Array("a","b")
val arr2=Array(1,2,3)
arr1.zip(arr2) 或者 arr1 zip arr2
结果是 Array(("a",1),("b",2))
这就是拉链操作
集合
Scala的集合有三大类:seq序列,set集合,map映射 所有的集合扩展自特质iterable
Nil表示空列表
不可变列表的追加元素 生成新的list ,原list不变
9::List(5,1) ::给定的头尾创建一个新的列表,它是右结合的如9::5::2::Nil = 9::(5::(2::Nil))
val list=List(0,1,2)
1::list = list.::(1) = 1 +: list=list.+:(1) 将1放到集合元素前面
list :+ 4 将4放到集合元素后面
list1 ++ list0(++是前面集合在前) 或者list1 ++: list0 = list1.:::(list0)(++:和.:::是后面集合在前)可以将两集合合并
可变列表的追加: 生成新list,原list不变
list1 ++= list2 合并(前面在前)
list :+ 0 list后面追加
list.insert(下标,0) 指定位置插入元素
set
val set =HashSet(1,2,3)
val set =new HashSet[Int]()
不可变的set
val set2=set + 4 //添加元素雨合并set
set ++ set2
可变的set
set3 += 0
set3.add(1)
set3++=set4 向set3中追加,并没有新生成set
set.remove(1)
set-=5
map
可变的map 添加数据
map+=(("hadoop",2))
map("spark")=1
map.put("storm",3)
map移除元素
map-="spark"
map.remove("hadoop")
list.grouped() 分组返回iterator
list.flatten 压扁 主要是将List(List(),List())
list.map(_.split(" ")).flatten =list.flatMap(_.split(" ")) 以空格切分然后压平
lazy 懒值 与java中的单例(懒汉式)在调用时执行
object LazyDemo2{
def init:Unit={
println("Call init()")
}
def main(args:Array[String]):Unit={
lazy val property=init()
println("after init")
println(property)
}
}
//运行结果 先after init,再call init(),再()。
wordcount
val lines=List("hello word","hello a")
val wc=lines.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).mapValue(_.size).toList.sortBy(_._2).reverse
val wc2=lines.flatMap(_.split(" ")).map((_,1)).mapValues(_.foldLeft(0)(_+_.2))
并行化 par 并行(同时几个线程工作) 并发(同一时间段处理同样任务)
折叠:fold
arr.fold(0)(_+_) //从左向右相加,第一个括号是初始值,会将初始值加进去
arr.aggregate(0)(_+_.sum,_+_)//聚合,第一个括号传初始值,第二个括号传两函数
arr.aggregate((0,0))((acc,num)=>(acc._1+num,acc._2+1),(par1,par2)=>(par1._1+par2._1,par1._2+par2._2))
并交差集 union intersect diff
类声明
val 修饰的类变量,相当于只有get,无set
var 有get和set
private 私有,只能在本类与本类伴生对象中使用
private[this] 对象私有变量,只有本类才能访问(伴生对象访问不到)
构造器 也就是构造方法,主构造器是类名后加参数
//给默认参数,前面没修饰,默认是val ,需要自定义get方法获取相应值,赋值时是可以传的(有默认参数)
class A(val name:String,var age:Int,faceValue:Int=90){
var gender :String =_
def getFaceValue()={
println(faceValue)
}
//辅助构造器
def this(name:String,age:Int,faceValue:Int,gender:String){
this(name,age,faceValue) //第一行必需调用主构造器
this.gender=gender
}
}
单例模式
object :修饰的类,是静态类。常用来存放工具方法与常量,高效共享单个不可变的实例,单例模式
apply 注入方法 unapply 提取方法
当看到直接使用类,而没有new的时候就是使用了object中的apply方法
class ApplyDemo(val name: String, val age: Int, val faceValue: Int) {
}
object ApplyDemo {
//注入方法
def apply(name: String, age: Int, faceValue: Int): ApplyDemo = new ApplyDemo(name, age, faceValue)
//提取参数
def unapply(a: ApplyDemo): Option[(String,Int,Int)] = {
if (a == null) {
None
} else {
Some(a.name,a.age,a.faceValue)
}
}
}
object ApplyTest{
def main(args: Array[String]): Unit = {
val applyDemo =ApplyDemo("aa",11,22)
applyDemo match {
case ApplyDemo("bb",age,faceValue) => println(s"age:$age,faceValue:$faceValue")
case _ =>print("None")
}
}
}
应用程序对象,也就是通过扩展App特质,不写main方法
特质与抽象类:
特质: 关键字 trait
可以定义声明变量,可以赋值也可以不赋值
可以定义方法,可以实现,也可以不实现
抽象类:关键字abstract
可以定义声明变量,可以赋值也可以不赋值
可以定义方法,可以实现,也可以不实现
区别:抽象类单继承,特质多实现
类型检查和转换
Scala java
判断对象是否为B类型的实例 obj.isInstanceOf[B] obj.instanceof B
将对象类型强转为B类型 obj.asInstanceOf[B] (B) obj
获取类型t的class对象 classof[t] t.class
private
private[day04] class PrivateDemo {} 包权限
class PrivateDemo private(name:String) {} //只有本类与伴生对象有权限访问(创建实例)
变量加private//本类及伴生对象能调用
private【this】 //对象私有,只有本类访问
模式匹配 如java中的switch ,但是匹配类型更多,功能更强
a match{
case str:String =>{}
case int: Int =>{}
case a:A=>{}
case _ =>{} //下划线是匹配所有。
}
//case 匹配的可以是不同的类型
case Array(4,a,b,c) => println(s case $a ,$b,$c) 个数匹配
case Array(3,_*)=>{} 前元素匹配
匹配元祖一样
匹配集合有 ::
样例类 可用于模式匹配
case object ChechObject
case class Submit(id:Int)
//case object 是单例的 case class需要构造参数
option类型
option 是样例类,some和none的父类,常用来匹配可能存在,可能不存在
val v =map.get("b") match{
case Some(i) =>i
case None =>0
}
偏函数
它是在大括号内没有match的一组case语句是一个偏函数,它是PartialFunction[A,B]的一个实例,a是参数类型,b是返回值类型,常用做输入模式匹配
def m1:PartialFunction[String,Int]={
case "one"=>1
case "s"=>2
}
def m2 (num :String):Int=num match {
case "one"=>1
case "s"=>2
}
这两种偏函数写法等价
Actor
Scala中的并发,基于事件模型,运用消息的接收发送来实现多线程,不共享数据,切actor内部是顺序执行
actor方法执行顺序:首先调用start()方法,再调用act(),再向actor发送消息
actor发送消息的格式: !异步无返回 !?同步等返回 !!异步有返回
ActorWordCount
object WordCount {
val buffer: ArrayBuffer[Future[Any]] = new ArrayBuffer[Future[Any]]()
val res: ArrayBuffer[Map[String, Int]] = new ArrayBuffer[Map[String, Int]]()
def main(args: Array[String]): Unit = {
val arrFile = Array("C://a.txt", "C://b.txt", "C://c.txt")
for (file <- arrFile) {
// val lines=Source.fromFile(file).getLines().toList
// val stringToInt: Map[String, Int] = lines.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).mapValues(_.size)
val task = new Task
task.start()
val value: Future[Any] = task !! SmTask(file)
buffer += value
}
while (buffer.size > 0) {
//
val dones: ArrayBuffer[Future[Any]] = buffer.filter(_.isSet)
for (done <- dones) {
val map: Map[String, Int] = done.apply().asInstanceOf[Map[String, Int]]
res += map
buffer -= done
}
println(res.flatten.groupBy(_._1).mapValues(_.foldLeft(0)(_+_._2)))
}
}
}
class Task extends Actor {
// override def start(): Actor = {
// println("task is started")
// }
override def act(): Unit = {
while (true) {
receive {
case SmTask(file) => {
val lines = Source.fromFile(file).getLines().toList
val map: Map[String, Int] = lines.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).mapValues(_.size)
sender ! map
}
}
}
}
}
case class SmTask(file: String)
方法转函数通过 将方法加开个下划线 如: m1 _
柯里化
柯里化是指:将接收两个参数的方法变成新的接收一个参数的方法或函数的过程
即:def m(x:Int)=(y:Int)=>x*y
val func =m(3)
func(5)
这可以简写成 m(3)(5) 也就是传入一个参数,返回的是一个函数。
柯里化可以想象成 闭包。
柯里化声明:def curry(x:Int)(y:Int)=x*y 或者 def curry(x:Int)=(y:Int)=>x*y
参数列表可以为空 像 def curry2()()=1
隐式转换和隐式参数
在scala cli 中查询 : implicit -v 查询Scala中的隐式转换 在Predef类中查询
implicit 修饰, 根据类型匹配
隐式转换相当于装饰模式和门面模式,是对方法增强,或者默认变量
隐式转换函数:需要implicit声明带有单个参数的函数
object MyPredef {
implicit def fileToRichFile(f:String)=new RichFile(f)
}
class RichFile(val file: String) {
def read(): String = {
Source.fromFile(file).mkString
}
}
object RichFile {
def main(args: Array[String]): Unit = {
//显示的实现了read方法
// val content: String = new RichFile("").read()
import MyPredef.fileToRichFile
val file =""
val content=file.read()
}
}
scala 的泛型
[B<:A] UpperBound B的父类是A类型,B的上界是A
[B>:A] LowerBound B的子类是A类型,B的下界是A
[B<%A] ViewBound B类型转A类型,需要隐式转换函数
[B:A] ContextBound 需要隐式的值
[-T] 逆变 作为参数类型 如果B是A的父类,T[B]是T[A]的子类
[+T] 协变 作为返回类型 如果B是A的父类,T[B]是T[A]的父类
泛型例子
class Teacher(val name:String,val faceValue:Int) extends Comparable[Teacher]{
override def compareTo(o: Teacher) = {
this.faceValue-o.faceValue
}
}
object Teacher{
def main(args: Array[String]): Unit = {
val t1=new Teacher("aa",99)
val t2=new Teacher("bb",999)
val arr =Array(t1,t2)
println(arr.sorted)
}
}
upperbound
class Girl(val name: String, val facevalue: Int, val age: Int) extends Comparable[Girl]{
override def compareTo(o: Girl) = {this.facevalue-o.facevalue}
}
class Choose[T<:Comparable[T]]{
def choose(first:T,second:T):T={
if (first.compareTo(second)>0) first else second
}
}
object Choose{
def main(args: Array[String]): Unit = {
val c=new Choose[Girl]
val g1=new Girl("a",1,2)
val g2=new Girl("b",3,4)
val girl: Girl = c.choose(g1,g2)
println(girl.name)
}
}
viewbound
class ViewBound[T<%Ordered[T]]{
def select(first:T,second:T):T ={
if (first>second) first else second
}
}
object ViewBound{
def main(args: Array[String]): Unit = {
import Actor.MyPredef.girlSelect
val viewBound: ViewBound[MyGirl] = new ViewBound[MyGirl]
val g1=new MyGirl("a",1,2)
val g2=new MyGirl("b",3,4)
val girl: MyGirl = viewBound.select(g1,g2)
println(girl.name)
}
}
class MyGirl(val name: String, val facevalue: Int, val age: Int) {
}
object MyPredef {
// implicit def fileToRichFile(f:String)=new RichFile(f)
implicit val girlSelect=( g : MyGirl)=>new Ordered[MyGirl]{
override def compare(that: MyGirl): Int = {
if (g.facevalue==that.facevalue){
that.age-g.age
}else{
g.facevalue-that.facevalue
}
}
}
}
akka
基于actor,提供了一个用于构建可扩展的(scalable)、弹性的(resilient),快速响应的(responsive)应用程序的平台
actor 可以创建监督actor,轻量级,异步非阻塞,高性能,简化抽象在并行与并发编程
spark的RPC
1 worker 把请求封装到caseclass中并序列化,发送到master
2 master 接受请求,并反序列化
3 master 返回结果
master 和 worker 信息过程:
1 启动master,启动后定期检查worker,检查是否有宕机的worker
2 启动worker,向master注册(worker的host,port,cores,memory等等)
3 master收到worker注册信息,保存,返回注册成功信息
4 worker收到注册成功信息后,定期向master发送心跳(报活),master收到心跳,更新报活时间
Master 类
class Master(val masterHost: String, val masterPort: String) extends Actor{
//用来储存worker 的注册信息
val idToWorker = new mutable.HashMap[String, WorkerInfo]()
//用来储存worker 的信息
val workers = new mutable.HashSet[WorkerInfo]()
//超时时间
val checkInterval = 15000
//prestart会被调用一次,在构造之后,receive 方法之前
override def preStart(): Unit = {
// 启动一个定时器,用于周期性检查超时worker
import context.dispatcher
context.system.scheduler.schedule(0 millis, checkInterval millis, self, CheckTimeOutWorker)
}
override def receive: Receive = {
case RegisterWorker(id, host, port, memory, cores) => {
if (!idToWorker.contains(id)) {
val workerInfo = new WorkerInfo(id, host, port, memory, cores)
idToWorker += (id -> workerInfo)
workers += workerInfo
println("a worker registered")
sender ! RegisteredWorker(s"akka.tcp://${Master.MASTER_SYSTEM}" + s"@$masterHost:$masterPort/user/${Master.MASTER_ACTOR}")
}
}
case HeartBeat(workerId) => {
//根据传过来的workerid来获取workinfo
val workerInfo = idToWorker(workerId)
// workinfo用来更新心跳时间
val currentTime = System.currentTimeMillis()
workerInfo.lastHeartbeatTime = currentTime
println("心跳,更新时间 HeartBeat")
}
case CheckTimeOutWorker => {
val currentTime = System.currentTimeMillis()
val toRemove: mutable.HashSet[WorkerInfo] = workers.filter(w => currentTime - w.lastHeartbeatTime > checkInterval)
toRemove.foreach(deadworker => {
//将超时worker移除
idToWorker -= deadworker.id
workers -= deadworker
println("remove worker")
})
}
}
}
object Master {
val MASTER_SYSTEM = "MasterSystem"
val MASTER_ACTOR = "Master"
def main(args: Array[String]): Unit = {
val host = args(0)
val port = args(1)
val configstr =
s"""
|akka.actor.provider="akka.remote.RemoteActorRefProvider"
|akka.remote.netty.tcp.hostname="$host"
|akka.remote.netty.tcp.port="$port"
""".stripMargin
//配置信息
val config: Config = ConfigFactory.parseString(configstr)
val actorSystem = ActorSystem(MASTER_SYSTEM, config)
//创建actor
val master = actorSystem.actorOf(Props(new Master(host, port)), "Master")
//退出方法
actorSystem.awaitTermination()
actorSystem.shutdown()
}
}
worker 类
class Worker(val host:String,val port:Int,val masterHost:String,val masterPort:Int,val memory:Int,val cores:Int) extends Actor {
val workerId =UUID.randomUUID().toString
var masterUrl:String =_
val heartBeat_Interval:Long = 10000//心跳间隔,必须小于超时时间
//master 地址
var master:ActorSelection=_
override def preStart(): Unit = {
master =context.actorSelection(s"akka.tcp://${Master.MASTER_SYSTEM}@$masterHost:$masterPort/user/${Master.MASTER_ACTOR}")
master ! RegisterWorker(workerId,host,port,memory,cores)
}
override def receive: Receive = {
case RegisteredWorker(masterUrl)=>{
this.masterUrl=masterUrl
//启动一个定时器,定时发送心跳
import context.dispatcher
context.system.scheduler.schedule(0 millis,heartBeat_Interval millis,self,SendHeartBeat)
println("启动一个定时器,定时发送心跳 RegisteredWorker")
}case SendHeartBeat =>{
//发送心跳之前进行检查
master ! HeartBeat(workerId)
println("发送心跳之前进行检查 SendHeartBeat")
}
}
}
object Worker{
val WORKER_SYSTEM="WorkerSystem"
val WORKER_ACTION="WorkAction"
def main(args: Array[String]): Unit = {
val host=args(0)
val port=args(1).toInt
val masterHost=args(2)
val masterPort=args(3).toInt
val memory=args(4).toInt
val cores=args(5).toInt
val configstr =s"""
|akka.actor.provider="akka.remote.RemoteActorRefProvider"
|akka.remote.netty.tcp.hostname="$host"
|akka.remote.netty.tcp.port="$port"
""".stripMargin
val config: Config = ConfigFactory.parseString(configstr)
val actorSystem = ActorSystem(WORKER_SYSTEM, config)
actorSystem.actorOf(Props(new Worker(host,port,masterHost,masterPort,memory,cores)),"Worker")
actorSystem.awaitTermination()
actorSystem.shutdown()
}
}
其他类
class WorkerInfo(val id:String,val host:String,val port:Int,val memory:Int,val core:Int) {
var lastHeartbeatTime:Long=_
}
trait RemoteMsg extends Serializable {
}
//master->self
case object CheckTimeOutWorker
//master ->worker
case class RegisteredWorker(masterUrl: String) extends RemoteMsg
//work -> master
case class RegisterWorker(id: String, host: String, port: Int, memory: Int, cores: Int) extends RemoteMsg
//worker ->self
case object SendHeartBeat
//worker -> master (heartbeat)
case class HeartBeat(workerId: String) extends RemoteMsg