元组
- 元组定义
与列表一样,与列表不同的是元组可以包含不同类型的元素。元组的值是通过将单个的值包含在圆括号中构成的。
- 创建元组与取值
- val tuple = new Tuple(1) 可以使用new
- val tuple2 = Tuple(1,2) 可以不使用new,也可以直接写成val tuple3 =(1,2,3)
- 取值用”._XX” 可以获取元组中的值
注意:tuple最多支持22个参数
//创建,最多支持22个 val tuple = new Tuple1(1) val tuple2 = Tuple2("zhangsan",2) val tuple3 = Tuple3(1,2,3) val tuple4 = (1,2,3,4) val tuple18 = Tuple18(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18) val tuple22 = new Tuple22(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) //使用 println(tuple2._1 + " "+tuple2._2) val t = Tuple2((1,2),("zhangsan","lisi")) println(t._1._2) |
- 元组的遍历
tuple.productIterator得到迭代器,进而遍历
//遍历 val tupleIterator = tuple22.productIterator while(tupleIterator.hasNext){ println(tupleIterator.next()) } |
- swap,toString方法
注意:swap元素翻转,只针对二元组
/** * 方法 */ //翻转,只针对二元组 println(tuple2.swap)
//toString println(tuple3.toString()) |
trait特性
- 概念理解
Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。
与接口不同的是,它还可以定义属性和方法的实现。
一般情况下Scala的类可以继承多个Trait,从结果来看就是实现了多重继承。Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait。
- 举例:trait中带属性带方法实现
注意:
- 继承的多个trait中如果有同名的方法和属性,必须要在类中使用“override”重新定义。
- trait中不可以传参数
trait Read { val readType = "Read" val gender = "m" def read(name:String){ println(name+" is reading") } } trait Listen { val listenType = "Listen" val gender = "m" def listen(name:String){ println(name + " is listenning") } } class Person() extends Read with Listen{ override val gender = "f" } object test { def main(args: Array[String]): Unit = { val person = new Person() person.read("zhangsan") person.listen("lisi") println(person.listenType) println(person.readType) println(person.gender)
} } |
- 举例:trait中带方法不实现
object Lesson_Trait2 { def main(args: Array[String]): Unit = { val p1 = new Point(1,2) val p2 = new Point(1,3) println(p1.isEqule(p2)) println(p1.isNotEqule(p2)) } } trait Equle{ def isEqule(x:Any) :Boolean def isNotEqule(x : Any) = { !isEqule(x) } } class Point(x:Int, y:Int) extends Equle { val xx = x val yy = y def isEqule(p:Any) = { p.isInstanceOf[Point] && p.asInstanceOf[Point].xx==xx }
} |
模式匹配match
- 概念理解:
Scala 提供了强大的模式匹配机制,应用也非常广泛。
一个模式匹配包含了一系列备选项,每个都开始于关键字 case。
每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。
- 代码及注意点
- 模式匹配不仅可以匹配值还可以匹配类型
- 从上到下顺序匹配,如果匹配到则不再往下匹配
- 都匹配不上时,会匹配到case _ ,相当于default
- match 的最外面的”{ }”可以去掉看成一个语句
object Lesson_Match { def main(args: Array[String]): Unit = { val tuple = Tuple6(1,2,3f,4,"abc",55d) val tupleIterator = tuple.productIterator while(tupleIterator.hasNext){ matchTest(tupleIterator.next()) }
} /** * 注意点: * 1.模式匹配不仅可以匹配值,还可以匹配类型 * 2.模式匹配中,如果匹配到对应的类型或值,就不再继续往下匹配 * 3.模式匹配中,都匹配不上时,会匹配到 case _ ,相当于default */ def matchTest(x:Any) ={ x match { case x:Int=> println("type is Int") case 1 => println("result is 1") case 2 => println("result is 2") case 3=> println("result is 3") case 4 => println("result is 4") case x:String => println("type is String") // case x :Double => println("type is Double") case _ => println("no match") } }
} |
偏函数
如果一个方法中没有match 只有case,这个函数可以定义成PartialFunction偏函数。偏函数定义时,不能使用括号传参,默认定义PartialFunction中传入一个值,匹配上了对应的case,返回一个值。
/** |
样例类(case classes)
- 概念理解
使用了case关键字的类定义就是样例类(case classes),样例类是种特殊的类。实现了类构造参数的getter方法(构造参数默认被声明为val),当构造参数是声明为var类型的,它将帮你实现setter和getter方法。
- 样例类默认帮你实现了toString,equals,copy和hashCode等方法。
- 样例类可以new, 也可以不用new
- 例子:结合模式匹配的代码
case class Person1(name:String,age:Int) object Lesson_CaseClass { def main(args: Array[String]): Unit = { val p1 = new Person1("zhangsan",10) val p2 = Person1("lisi",20) val p3 = Person1("wangwu",30)
val list = List(p1,p2,p3) list.foreach { x => { x match { case Person1("zhangsan",10) => println("zhangsan") case Person1("lisi",20) => println("lisi") case _ => println("no match") } } }
} } |
隐式转换
隐式转换是在Scala编译器进行类型匹配时,如果找不到合适的类型,那么隐式转换会让编译器在作用范围内自动推导出来合适的类型。
- 隐式值与隐式参数
隐式值是指在定义参数时前面加上implicit。隐式参数是指在定义方法时,方法中的部分参数是由implicit修饰【必须使用柯里化的方式,将隐式参数写在后面的括号中】。隐式转换作用就是:当调用方法时,不必手动传入方法中的隐式参数,Scala会自动在作用域范围内寻找隐式值自动传入。
隐式值和隐式参数注意:
1). 同类型的参数的隐式值只能在作用域内出现一次,同一个作用域内不能定义多个类型一样的隐式值。
2). implicit 关键字必须放在隐式参数定义的开头
3). 一个方法只有一个参数是隐式转换参数时,那么可以直接定义implicit关键字修饰的参数,调用时直接创建类型不传入参数即可。
4). 一个方法如果有多个参数,要实现部分参数的隐式转换,必须使用柯里化这种方式,隐式关键字出现在后面,只能出现一次
object Lesson_ImplicitValue { |
- 隐式转换函数
隐式转换函数是使用关键字implicit修饰的方法。当Scala运行时,假设如果A类型变量调用了method()这个方法,发现A类型的变量没有method()方法,而B类型有此method()方法,会在作用域中寻找有没有隐式转换函数将A类型转换成B类型,如果有隐式转换函数,那么A类型就可以调用method()这个方法。
隐式转换函数注意:隐式转换函数只与函数的参数类型和返回类型有关,与函数名称无关,所以作用域内不能有相同的参数类型和返回类型的不同名称隐式转换函数。
class Animal(name:String){ |
- 隐式类
使用implicit关键字修饰的类就是隐式类。若一个变量A没有某些方法或者某些变量时,而这个变量A可以调用某些方法或者某些变量时,可以定义一个隐式类,隐式类中定义这些方法或者变量,隐式类中传入A即可。
隐式类注意:
1).隐式类必须定义在类,包对象,伴生对象中。
2).隐式类的构造必须只有一个参数,同一个类,包对象,伴生对象中不能出现同类型构造的隐式类。
class Rabbit(s:String){ |
Actor Model
- 概念理解
Actor Model是用来编写并行计算或分布式系统的高层次抽象(类似java中的Thread)让程序员不必为多线程模式下共享锁而烦恼,被用在Erlang 语言上, 高可用性99.9999999 % 一年只有31ms 宕机Actors将状态和行为封装在一个轻量的进程/线程中,但是不和其他Actors分享状态,每个Actors有自己的世界观,当需要和其他Actors交互时,通过发送事件和消息,发送是异步的,非堵塞的(fire-andforget),发送消息后不必等另外Actors回复,也不必暂停,每个Actors有自己的消息队列,进来的消息按先来后到排列,这就有很好的并发策略和可伸缩性,可以建立性能很好的事件驱动系统。
Actor的特征:
- ActorModel是消息传递模型,基本特征就是消息传递
- 消息发送是异步的,非阻塞的
- 消息一旦发送成功,不能修改
- Actor之间传递时,自己决定决定去检查消息,而不是一直等待,是异步非阻塞的
什么是Akka
Akka 是一个用 Scala 编写的库,用于简化编写容错的、高可伸缩性的 Java 和Scala 的 Actor 模型应用,底层实现就是Actor,Akka是一个开发库和运行环境,可以用于构建高并发、分布式、可容错、事件驱动的基于JVM的应用。使构建高并发的分布式应用更加容易。
spark1.6版本之前,spark分布式节点之间的消息传递使用的就是Akka,底层也就是actor实现的。1.6之后使用的netty传输。
- 例:Actor简单例子发送接收消息
import scala.actors.Actor class myActor extends Actor{
def act(){ while(true){ receive { case x:String => println("get String ="+ x) case x:Int => println("get Int") case _ => println("get default") } } } } object Lesson_Actor { def main(args: Array[String]): Unit = {
//创建actor的消息接收和传递 val actor =new myActor() //启动 actor.start() //发送消息写法 actor ! "i love you !" } } |
- 例:Actor与Actor之间通信
case class Message(actor:Actor,msg:Any) class Actor1 extends Actor{ def act(){ while(true){ receive{ case msg :Message => { println("i sava msg! = "+ msg.msg)
msg.actor!"i love you too !" } case msg :String => println(msg) case _ => println("default msg!") } } } } class Actor2(actor :Actor) extends Actor{ actor ! Message(this,"i love you !") def act(){ while(true){ receive{ case msg :String => { if(msg.equals("i love you too !")){ println(msg) actor! "could we have a date !" } } case _ => println("default msg!") } } } } object Lesson_Actor2 { def main(args: Array[String]): Unit = { val actor1 = new Actor1() actor1.start() val actor2 = new Actor2(actor1) actor2.start() } } |
WordCount
import org.apache.spark.SparkConf import org.apache.spark.SparkContext import org.apache.spark.rdd.RDD import org.apache.spark.rdd.RDD.rddToPairRDDFunctions object WordCount { def main(args: Array[String]): Unit = { val conf = new SparkConf() conf.setMaster("local").setAppName("WC") val sc = new SparkContext(conf) val lines :RDD[String] = sc.textFile("./words.txt") val word :RDD[String] = lines.flatMap{lines => { lines.split(" ") }} val pairs : RDD[(String,Int)] = word.map{ x => (x,1) } val result = pairs.reduceByKey{(a,b)=> {a+b}} result.sortBy(_._2,false).foreach(println)
//简化写法 lines.flatMap { _.split(" ")}.map { (_,1)}.reduceByKey(_+_).foreach(println)
} } |