Scala基本语法

来源:互联网 发布:软件报价方案模板 编辑:程序博客网 时间:2024/05/22 23:49

JavaScala运行时都需要JRE,且JavaScala都需要编译成字节码后才能在JVM上运行,实际工程中Scala一般会调用JavaAPI

 

var :变量值可改变

val :变量值不可改变

 

Object相当于java中的public static class修饰符(包含静态成员和方法),object不是对象,可以通过Objectapply方法控制对象的创建(单例模式,采用工厂模式)

 

抽象类的Object伴生对象中的apply()实际上是调用抽象类的子类构造方法创建,比如Graph.apply()实际上是调用了GraphImpl的构造方法

 

AnyScala中所有基本类型的父类

AnyRefScala的所有引用类型的父类

NilScala中空引用

 

函数背后实际是类和对象,在运行时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

实际上是fori<-array//遍历array的每个元素

for(i<- 1 to 10){//循环10

}

for(i<-0 until(array.length,step)){//0array.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:_*)//调用arrayRange)每个元素

7.lazy延迟执行

只有当访问时才执行,类成员变量初始化延迟执行

lazy val i=10

I

8.异常处理

try{

监控块

}

catch{

case ex:IOExceptioon=>{

异常处理

}

case ex:FileNotFound=>{

异常处理

}

}

finally{
善后

}

9.ArrayArrayBuffer

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)//array3的倍数翻倍

12.Map集合类

val map=Map(“key”->value)//Map不可变,当发生改变时则会生成新的mapgetOrElse(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

}       

内部类ParentChild,每一个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.函数式编程

1def 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{//xOption对象

case Some(t) =>{有值对t处理}

case None=> {无值处理}

}

6)匹配值 case value

7)匹配类型 case typeType

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.异步并发模型ActorSpark 源码Master sendmessage/Worker.receive() case 模式匹配 sendToMaster发送反馈)Driver中的并发编程DAGScheduler->DAGSchedulerEventProcessLoop->LinkedBlockingDeque->Thread.run()线程不断take()从队列中取eventonReceive(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]  //协变即如果AB的子类,则Person[A]Person[B]的子类

class Person[-T]  //逆变则相反

class Meeting[+T] //协变,def participateMeeting指定meetingMeeting[Engineer]类型,由于ExpertEngineer的子类,因此在实际调用时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] //AB的隐式转换类型(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可能需要shuffleshuffle=true

7)数据调度弹性:DAG,Task均与资源管理器无关,先分配资源后执行Task

24.Spark耗时的四种场景

1)缓存耗时

2)计算链条过长(血统过长)

3)Checkpoint持久化

4)Shuffle操作

 

21.Scala继承

Scala继承能复用代码,Scala类继承时不能继承其伴生对象,RDD的抽象方法compute()getPartitions()

 

RDD默认构造器(Primary Constructor,实例化初始状态,初始化成员,初始化动作)需要传入sparkContextDependencies,后面的def 方法中可直接使用,自定义构造器中必须包含Primary Constructor,都会实例化对象,

 

isInstanceOfobj isInstanceOf(Object)//判断obj是否是Object的实例

asInstanceOf obj asInstanceOf(Object)//obj转换为Object

obj.getClass()//获得obj运行时的类型

classof[T]//T类型

 

22.面向接口编程

1Trait既可以包含抽象方法又可以包含已实现方法(工具类),with连接多接口Trait

2)抽象属性:

val name:String //val 变量必须指定变量的类型,则称为抽象属性 

3)对象混入接口

 

可以随时扩展第三方实现,RichLogger就是混入的接口

 

23.Scala集合类

RDD本身是一个集合,RDD.getPartitions()返回Array[Partition],每个Partition本身又是由多条记录组成,RDD.getDependencies()返回Seq[Dependency]

1)集合类必须继承IterableTrait

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包中的ColorFont

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.AnyAnyRef

Any类似于Java中的Object,即是所有的基类,可实现所有的接口方法(equals,hashCode)

 

28.Scala提取器和注解

1)注解

@volatile 多线程并发控制,多线程操作全局变量的过程,首先会将全局变量拷贝到本地线程,执行完成后更新全局变量,每次获取该值时强制刷新以获取最新值

@deprecated 被废弃的接口,有可能在大的版本更新中删除

@developerApi 框架开发使用的 API

@Experimental 实验测试功能

@transient 不参与序列化和反序列化,只存在本进程

2)提取器

val person=Person.apply(“Spark”,6) //通过Objectapply()创建实例person

val Person(name,age)=person //调用Objectunapply()提取personnameage并赋值 

 

自定义提取器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中所有引用类的父类包括,天生对线程有支持(waitnotify等)

 

AnyVal(基本类型Double Int的父类)

Any->AnyRef(自定义类)/AnyVal(基本类型)

NothingNull是所有继承的最低端,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)使用OptionNone/Some,None解决NullOption可直接调用map等算子操作

5)使用伴生对象的apply工厂方法构造类或者抽象类的实例对象

 

35.Scala面向对象内幕实战解密

object HelloFileOpps extends App{//相当于继承了Appmain方法,args来自于Appmain方法,Trait App extends DelayedInit(延迟初始化){

private val initCode=new ListBuffer[() => Unit] 

override def delayedInit(body:=>Unit){

initCode+=(()=>body)  //HelloFileOpps中的bodyBodyObject.apply创建body)迁移到Appmain方法中,body保存在AppinitCode

}

 

36.隐式转换实质

Import Student._  //实际上会导入Class StudentObject Student的所有成员

隐式转换转换作用域:

本地>>Object伴生对象中的隐式成员>import Student.content(具体导入)>import Student._(模糊导入)

原创粉丝点击