函数式编程
- scala 中函数可以独立存在,不需要依赖任何类和对象
- 将函数赋值给变量
使用def定义方法和函数
函数,方法的区别是出现的位置不同,在类里面是方法 ,在类外是函数
//将函数赋值给变量时,必须在函数后加上空格和下划线
def say(name:String) {println("hello"+name)}
val sayFunc=say _
sayFunc("leo")
- 匿名函数
没有名字的函数称为匿名函数
可以直接定义函数后将函数赋值给某个变量,也可以将匿名函数传入其它函数中
定义匿名函数的语法规则:(参数名:参数类型)=>函数体
//匿名函数
val aa=(name:String)=>println("hello"+name)
- 高阶函数
接受其他函数作为参数的函数称为高阶函数
- 可以直接将某个函数作为参数传入其他函数
- 将函数作为返回值
//将函数作为参数
val say=(name:String) => println("hello"+" "+name)
def greeting(func:(String) => Unit,name:String){func(name)}
greeting(say,"Tom")
//将函数作为返回值
def getGreetingFunc(msg:String)=(name:String)=>println(msg+","+name )
val greetingFunc=getGreetingFunc("hello")
greetingFunc("leo")
Map和faltMap的区别
lines.map(x=>x.split(" ")).collection
//faltMap:faltten Map ,先执行map,后执行flatten(扁平化)
lines.flatmap(x=>x.split(" ")).collection
//
line.map(x=>x.split(" ")(2) ) //取新形成数组的索引为2 的值
lines.first //只取第一条数据
- 高阶函数的类型推断
高阶函数可以自动推断参数类型,不需要写明类型
如果函数只有一个参数,可以省略小括号
greeting ((name:String)=>print("hello"+ " "+name),"tom")
greeting (name=>print("hello"+ " "+name),"tom")
- scala的常用高阶函数
//map对传入的每一个元素进行映射,返回一个处理后的结果
Array(1,2,3,4,5).map(x=>2* x) //完整版
Array(1,2,3,4,5).map(2* _) //简写版
//foreach对传入的每一个元素都进行处理,但是没有返回值
(1 to 9 ).map("@"*_).foreach(println _)
//对比
(1 to 9 ).map("@"*_)
//filter:对传入的每一个元素都进行条件判断,
如果对元素返回true,则保留该元素,否则过滤掉该元素
(1 to 20 ).filter(_%2==0)
//reduceLeft:从左侧元素开始,进行reduce操作,
及先对元素1和元素2进行处理,将结果与元素3进行处理,以此类推,
即为reduce
(1 to 9).reduceLeft(_*_) //等同于1*2*3*4*5*6*7*8*9
(1 to 9).reduceLeft(_+_)
(1 to 9).reduceLeft((x,y)=>x+y)
(1 to 9).reduce((x,y)=>x+y)
//sortWith:对元素进行两两对比,进行排序
Array(3,2,5,9,8,6,1).sortWith(_<_)
//
val list=List (List(1,2),List(3,4,5),List(6,7,8,9))
list.filter(x=>x.length>2)
list.filter(x=>x.contains(2))
.filter(x=>x.length==6 && 7< = <10 &&kw.contains("百度影音"))
函数式编程的集合操作
- scala的集合体系结构
集合体系主要包括:Iterable,Seq,Set,Map
其中Iterable是所有集合trait的根trait
scala的集合是分成可变集合和不可变集合
可变集合是指元素可以动态修改(scala.collection.mutable)
不可变集合的元素在初始化后就无法修改了(scala.collection.immutable)
Seq中包含了Range,ArrayBuffer,List等子trait
Rang表示一个序列,通常可以使用“1 to 10”这种语法产生一个Range
ArrayBuffer类似java中的ArrayList - list
List表示一个不可变的列表
List有head,tail,
head表示List的第一个元素
tail代表第一个元素后的所有元素list.head,list.tail
List有特殊的操作符::,用于将两个List合并成一个List
如果一个List只有一个元素,那么它的head就是这个元素,tail就是Nil
Nil是一个空的List,定义为List[Nothing]
//创建List
val list=List(1,2,3,4)
val list1=0::list
val list2=list:::list1
val list3=list::list1 //list整体作为一个元素
//案例
def decorator(list:List[Int],prefix:String){
if(list!=Nil){
println(prefix+list.head)
println(list)
decorator(list.tail,prefix)
}
}
val list=List(6,7,8,9,10)
decorator(list,"@@")
- LinkedList
代表一个可变的列表,使用elem可以引用其头部,使用next可以引用其尾部
val list=scala.collection.mutable.LinkedList(6,7,8,9,10)
list.elem
list.next
//
val list=scala.collection.mutable.LinkedList(6,7,8,9,10)
var currentList=list
while(currentList!=Nil){
currentList.elem=currentList.elem*2
currentList=currentList.next
}
//小技巧
val tuple=("Tom",(20,90))
tuple._1
tuple._2
tuple._2._2
- Set
代表一个没有重复元素的集合
set不保证插入顺序,也就是说Set是乱序的
//无序性
val s = new scala.collection.mutable.HashSet[Int]();s+=1;s+=2;s+=5
//LinkHashSet会使用链表维护插入顺序
val s1 = new scala.collection.mutable.LinkedHashSet[Int]();s+=1;s+=2;s+=5
//SortedSet会根据key进行排序
val s2 =scala.collection.mutable.SortedSet("orange","apple","banana")
- 集合的函数时编程
//为每一个元素添加前缀
List("Tom","sam").map("name is"+_)
//将多行句子拆分成单词
List("hello world","you me").flatMap(_.split(" "))
//打印每一个单词
List("i","have","a","boy").foreach(println(_))
//将连个list进行关联
List("Leo","jack").zip(List(100,90))
- 函数式编程案例:统计多个文本内的单词总数
val lines=scala.io.Source.fromFile("C://Users//Lyuc//Desktop//asdasd.txt").mkString
val linesss=List(lines)
linesss.flatMap(_.split("\t")).map((_,1)).map(_._2).reduceLeft(_+_)
//完整版
lines.flatMap(x=>split("\t")).map(x=>x,1).map(x=>x._2).reduce(_+_)
模式匹配与类型参数
可以进行模式匹配,类型匹配,对Array,List的元素情况匹配,对case class(样例类)进行匹配,对有值,没值(Option)进行匹配
- 模式匹配语法基础
java的switch case仅能匹配变量的值
scala的match case 可以匹配变量的类型,集合的元素,有值,没值
如果值为下划线(_):不满足以上所有情况
只要满足一个case分支并处理了,就不会继续判断其他case分支
语法:变量 match { case 值 => 代码 }
def score(grade:String){
grade match{
case "A"=>println("very good")
case "B"=>println("good")
case "C"=>println("soso")
case "D"=>println("you mother is in the way")
}
}
- 在模式匹配中使用if守卫
在case后的条件判断中增加一个if守卫,进行双重过滤
case _if name=="leo"=>println("no zuo no die")
- 在模式匹配中进行变量赋值
可以将默认情况(_)替换为一个变量名,在模式匹配下会将要匹配的值,赋值给这个变量,从而可以在后面处理语句中使用要匹配的值
def score(name:String,grade:String){
grade match{
case "A"=>println(name+"very good")
case "B"=>println(name+"good")
case "C"=>println(name+"soso")
case "D"=>println(name+"you mother is in the way")
case _grade if name=="leo" => println(name+"no zuo no die"+_grade)
case _grade =>println("you must work hard"+_grade)
}
}
- 对类型进行模式匹配
可以直接匹配类型
语法格式:case 变量:类型 => 代码
import java.io._
def processException(e:Exception){
e match{
case e1:IllegalArgumentException => println("you have illegal arguments!"+e1)
case e2:FileNotFoundException => println("cannot find the file you need or write!"+e2)
case e3:IOException => println("you got an error while you were doing IO"+e3)
case _:Exception => println("cannot know which exception you you have!")
}
}
- 对Array和List的元素进行模式匹配
对Array进行模式匹配,可以匹配带有指定元素的数组,带有指定个数的元素,以某个元素开头的数组
对List进行模式匹配,与Array相似,但是要使用::操作符
//对Array进行模式匹配
def greeting(arr:Array[String]){
arr match{
case Array("Leo") => println("hello,leo")
case Array(gril1,gril2,gril3) => println("hello"+gril1+"and"+gril2+"and"+gril3)
case Array("Leo",_*) => println("=====hello,leo=====")
case _=> println("who are you ?")
}
}
val arr1=Array("Leo")
val arr2=Array("Amy","jen","jeny")
val arr3=Array("Leo","sam")
val arr4=Array("asdasd")
greeting(arr1)
//对List的元素进行模式匹配
//
def greeting(list:List[String]){
list match{
case "Leo"::Nil => println("hello,leo")
case gril1::gril2::gril3::Nil => println("hello"+gril1+"and"+gril2+"and"+gril3)
case "Leo"::tail => println("=====hello,leo=====")
case _=> println("who are you ?")
}
}
val list1=List("Leo")
val list2=List("Amy","jen","jeny")
val list3=List("Leo","sam")
val list4=List("asdasd")
greeting(list1)
- case class(样例类)与模式匹配
样例类,使用case class声明
只定义field,并由scala直通提供getter和setter方法,没有method
case classde 主构造函数接受的参数通常不需要使用val,var修饰,scala会自动使用val使用
scala自动为case class定义了伴生对象,也就是object,并且定义了apply()方法,该方法接受主构造函数中相同的参数,并放回case class对象
class person
case class Teacher(name:String,subject:String) extends person
case class Student(name:String,classroom:String) extends person
def judgeldentify(p:person){
p match{
case Teacher(name,subject) => println("Teacher,name is"+ name+",subject is"+subject)
case Student(name,classroom) => println("studnet,name is"+ name+",classroom is"+classroom)
case _ => println("what the fuck! who you are!")
}
}
val p1 = new Student("tom","classrom1")
val p2 = new Teacher("sam","BD")
judgeldentify(p1)
judgeldentify(p2)
- Option与模式匹配
scala中有一种特殊的类型——Option
Option有两种值,一种是Some(表示有值),一种是None(表示没有值)
Option通常用在匹配模式中,用于判断某个变量是否有值
val grades =Map("Leo"->"A","jake"->"B","sam"->"C")
def getGrade(name:String){
val grade=grades.get(name)
grade match{
case Some(grade)=>println("your grade is "+ grade)
case None=>println("sorry")
}
}
类型参数
*泛型类
class student[T](val localid:T){
def getSchool(hukouid:T)="S-"+hukouid+"-"+localid
}
val leo = new student[Int](111)
val jack = new student(1)
leo.getSchool(123)
jack.getSchool(456)
println(jack.getSchool(456))
- 泛型函数
def getCard[T](content:T)={
if(content.isInstanceOf[Int])"card:001"+content
else if (content.isInstanceOf[String]) "this is you card"+content
else "card:"+content
}
getCard[String]("hello world")
- 协变和逆变
class Master
class Professional extends Master
class Card[+T](val name:String){
def enterMeet(card:Card[Master]){
println(name+"======"+"welcome to have this meeting!")
}
}
val aa=new Card[Master]("tom")
val bb= new Card[Professional]("jack")
aa.enterMeet(aa)
bb.enterMeet(bb)
aa.enterMeet(bb)
bb.enterMeet(aa)
//逆变
class Master
class Professional extends Master
classCard[-T](val name:String){
def enterMeet(card:Card[Professional]){
println(name+"--------"+"welcome to have this meeting!")
}
}
val aa=new Card[Master]("tom")
val bb= new Card[Professional]("jack")
隐式转换和隐式参数
- 隐式函数
隐式转换函数:implicit conversion function
class Num{ }
class RichNum(num:Num){
def rich{
print("this is a richInt")
}
}
object ImplicitDemo{
implicit def num2richNum(num:Num)=new richNum(num)
def main(args:Array[String]):Unit={
val num= new Num()
num.rich()
}
}
隐式函数
object Int2StringTest{
implicit def int2String(i:Int)=i.toString()
def main(args:Array[String]):Unit={
print(5.length())
}
}
隐式导入函数
import ImplicitPro.Int2StringTest._将Int2String内部的额成员导入到相应的作用域内,否则无法调用隐式函数
import ImplicitPro.Int2StringTest._
object ImplicitTest{
def main(args:Array[String]):Unit={
println(4.length())
}
}
- 隐式转换
class SpecialPerson(val name:String)
class Student(val name:String)
class Older(vla name:String)
implicit def object2SpecialPerson(obj:Object):SpecialPerson={
if(obj.getClass ==classOf[Student]){val stu =obj.asInstanceOf[Student];new SpecialPerson(stu,name)}
else if (obj.getclass==classOf[Older]){ val older = obj.asInstanceOf[Older];new SpecialPerson(older.name)}
else Nil
}
var ticketNumber=0
def buySpecialTicket(p:SpericaPerson)={
ticketNumber+=1
"T-"+ticketNumber
}
def mian(args:Array[String]):Unit={
val stu = new Studnet("asdasd")
val Older = new Older("qweqwe")
buySpecialTicket(stu)
buySpecialTicket(old)
}
- 使用隐式转换加强现有类型
- 隐式参数
class signPen{
def write(context:String)=println(context)
}
implicit val signPen = new SignPen
def SignForExam()
闭包
函数在比变量不处于有效的作用域的时,依然能进行访问,称为闭包
def aa(msg:String)=(name:String)=>println(msg+","+name)
val bb=aa("hello")
val cc=aa("hi")
Currying(柯里化函数)
将原来接受两个参数的一个函数,转化为两个函数,第一个函数接受原来的第一个参数。然后返回接受原来接受第二个参数的第二个函数
在函数的调用过程中就变味了两个函数连续调用的形式
def sum(a:Int,b:Int)=a+b
sum(1,1)
def sum1(a:Int),(b:Int)=a+b
sum1(1)(1)
Actor
类似java中的多线程
scala的Actor尽可能的避免锁和共享状态,还可以避免死锁等一系列多线程编程问题
Spark使用的分布式多线程框架是Akka,Akka也实现了类似Scala Actor模型,核心概念也是Actor
- Actor 的创建,启动和消息的收发
scala提供Actor trait来让我们方便的今次那个actor多线程编程
只要重写act方法即可
使用start()方法启动actor
使用!向actor发送消息
actor内部使用receive和模式匹配接收消息
import scala.actors.Actor
class HelloActor extends Actor{
def act(){
while (true){
receive{
case name:String=>println("hello"+" "+name)
}
}
}
}
object Actoremo {
def main(args: Array[String]): Unit = {
val helloActor=new HelloActor
helloActor.start()
helloActor!"leo"
}
}
- 收发case class类型的消息
scala中一个actor可以给其他actor直接发送消息,使用“actor!消息”的语法模式
通常使用样例类,即case class 来作为消息惊醒发送,然后在actor接收消息,可以使用模式匹配功能来进行不同消息的处理
case class Login(username:String,password:String)
case class Register(username:String,password:String)
class UserManageActor extends Actor{
def act(){
while(true){
receive{
case Login(username,password)=>println("login username is"+username+", password is"+password)
case Register(username,password)=>println("register username is"+username+", password is"+password)
}
}
}
}
val userManageActor = new UserManageActor
userManageActor.start()
userManageActor!Register("leo","123123");
userManageActor!Loginr("leo","123123");
- Actor之间互相收发消息
如果两个Actor之间要是互相收发消息,有一个scala向另一个actor发行消息,同时带上自己的引用,其他actor收到自己的消息时,直接通过发送消息的actor的引用,可以回复消息
import scala.actors.Actor
case class Message(content:String,sender:Actor)
class LeoTelephoneActor extends Actor{
def act(){
while(true){
receive{
case Message(content,sender)=>{
println("leo telephone:" +context );sender!"i am leo, please call me after 10 hour later"
}
}
}
}
}
class jackTelephoneActor(val leo TelephoneActor:Actor) extends Actor{
def act(){
leo TelephoneActor!Message("hello,leo,I am jack."this)
receive{
case response:String=>println("jack telephone:"+respones)
}
}
}