一、概论
Scala源自Java
- Scala构建在JVM之上
- Scala与Java兼容、互通
Scala的优势
- 多范式编程:面向对象编程、函数式编程
- 表达能力强,代码精简
- 最重要的特性:类型推断
大数据与Scala
- Spark采用Scala语言设计
- 提供的API更加优雅
- 基于JVM的语言更融入Hadoop生态圈

二、Scala 安装 – Window
1. 下载安装包解压
https://downloads.lightbend.com/scala/2.11.8/scala-2.11.8.msi
2. 设置环境变量
SCALA_HOME D:\Kaifa\scala-2.11.8 PATH %SCALA_HOME%\bin CLASSPATH %SCALA_HOME%\bin;%SCALA_HOME%\lib\dt.jar;%SCALA_HOME%\lib\tools.jar
3. 测试
WIN+R cmd scala -version
三、Scala 安装 – Linux
1. 下载安装包
wget https://downloads.lightbend.com/scala/2.11.8/scala-2.11.8.tgz
2. 解压
tar -zxf scala-2.11.8.tgz mv scala-2.11.8 /usr/local/scala
3. 设置环境变量
vi /etc/profile export SCALA_HOME=/usr/local/scala export PATH=$PATH:$SCALA_HOME/bin . /etc/profile
4. 测试
scala -version :quit
四、Scala 安装 – IDEA插件
1. 添加插件并重启IDEA
File – Setting – Plugin Scala install
2. 创建无特征Mvn项目,导入Mvn依赖
<properties> <scala.version>2.11.8</scala.version> </properties> <dependencies> <dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-library</artifactId> <version>2.11.8</version> </dependency> </dependencies>
3. 首次创建Scala文件
new file -> Hello.scala create scala
4. 创建入口,编程名言
object Hello { def main(args: Array[String]): Unit = { print(“hello world”) } }
5. =)
hello world
五、Scala 概述
面向对象特性
- 每个值都是对象
- 对象的数据类型和行为由类(Class)和特征(Trait,类似于interface)描述
- 利用特质实现混入式多重继承
函数式编程
- 每个函数都是一个值
- 支持高阶函数、柯里化(currying)、样例类(case class)及模式匹配……
Scala是静态类型语言
扩展性:隐式类、字符串插值
六、Scala 变量与常量
变量 Var(variable)
赋值后可以改变,生命周期中可以被多次赋值
var 变量名称:类型=xxx var name = “jason” name:string = jason var name:String = “jason” //直接调用java的String
常量 Val(value)
赋值后不可变,类似于Java中的final变量
尽量使用val,val没有线程安全问题,效率较高
val 常量名称:类型=xxx val money = 100 money:int = 100
使用类型别名定义变量
type关键字
type 类型别名=类型 type T = String //defined type alias T val name:T = “jason” name:T = jason
七、Scala 关键字列表
39 个关键字
11 个符号


八、Scala 数据类型
Scala与Java有着相同的原始数据类型
数据类型
|
描述
|
Byte
|
8位有符号整数。数值区间-128 ~ 127
|
Short
|
16位有符号整数。数值区间-32768 ~ 32767
|
Int
|
32位有符号整数。数值区间 -2147483648 ~ 2147483647
|
Long
|
64位有符号整数。 -9223372036854775808 ~ 9223372036854775807
|
Float
|
32位IEEE 754 单精度浮点数
|
Double
|
64位IEEE 754 双精度浮点数
|
Char
|
16位无符号Unicode字符。区间值为U+0000 ~ U+FFFF
|
Boolean
|
true或false
|
String
|
等于java.lang.String
|
九、Scala 数据类型层次结构
Any
|
所有类型的超类(顶级类型)
|
AnyVal
|
表示值类型的超类
|
AnyRef
|
表示引用类型的超类,对应java.lang.Object
|
Unit
|
表示无值,类似Java中的void
|
Nothing
|
所有类型的子类
|
Null
|
表示null或空引用
|
YourClass
|
自定义类
|
String
|
隶属于AnyRef
|
ScalaObject
|
隶属于AnyRef
|

十、字符串插值
s 插值器
- 允许将变量引用、表达式直接插入字面字符中
val name=”James” println(s”Hello,$name”) //Hello,James print(s”1+1=${1+1}”) //1+1=2 println(s”hello+${6*4}”) //hello+24
f 插值器
- 指定格式化输出
val height=1.9d val name=”zhangsan” println(f”$name%s is $height%2.2f”) //zhangsan is 1.90
raw 插值器
- 忽略换行符、制表符等符号,直接输出原始值
s”a\nb” //将输出换行符 raw”a\nb” //输出原始字符
十一、Scala 条件控制
if 语句
val x=10 if(x>0){ print(“x大于0”) }
if…else 语句
val x=10 if(x>10){ print(“x大于10”) }else{ print(“x小于等于10”) } //:paste val x=10 if(x>10){ print(“x大于10”) }else if(x==10){ print(“x等于10”) }else{ print(“x小于10”) }
Case
o match{ case 1 => println(“yes”) case _ => println(“no”) } var s = “hello” throwableToLeft { s.toUpperCase } match { case Right(s) => println(s) case Left(e) => e.printStackTrace }
十二、条件语句返回值
Scala任何表达式都有返回值
val x=10 val y=if(x==10) x+1 else x //单行表达式可以省略{} //y=?
代码块“{…}”也是表达式,返回值为最后一个表达式结果
val x=10 val y={ println(“我是代码块”) x+1 } //我是代码块 //y: Int = 11 val x=10 val y={ x+1;print(“我是代码块”) } //一行内有多个表达式,需要使用“;”分隔 //我是代码块y: Int = 11
十三、Scala 循环控制-1
while循环
- Scala中可以不用在语句结束位置显示地使用分号(;)
var num: Int = 0; while ( num < 100 ) { println( num );num = num + 1; } var num: Int = 0; do { println( num );num = num + 5; } while ( num < 200 }
for循环
val num:Int = 10; for ( i <- 1 to num ) { println( i * 100 ); } //until:后开区间,不取后值 for { i: Int <- 1 until 100 } { val y = 2*i; println( y ); }
模拟continue和break
//1. 利用return达到break的效果 def main(args: Array[String]): Unit = { var a = random.nextInt(90)+10 test(a) def test(x:Int): Unit ={ for(i <- 1 to x){ println(i) if(i==10){ return } } } } //2. 使用breakable方法停止循环 import scala.util.control.Breaks._ def main(args: Array[String]): Unit = { test() def test(): Unit = { println(“Start”) val l = List(1,2,3,4,5,6,7,8,9,10) breakable{ for(x <- l){ println(2*x) if(x > 6)break } } println(“Done”) } } //3. 使用循环条件达到continue效果 for (i <- 1 to 10; if i % 2 == 0) { val y = 2 * i println(y) }
十四、Scala 循环控制-2
中断
- by 2:表示步长为2
import scala.util.control.Breaks._ val num:Int = 10; for ( i: Int <- 1 to num by 2 ) { if(i>=5) break; println( i * 100 ); }
for循环过滤
- 多个条件时使用分号(;)
for(i<-1 to num by 2;if i%3==0;if i<=5){println(i)} val num:Int = 10; for ( i: Int <- 1 to num; if i%2==0;if i>5 ) { println( i * 100 ); }
十五、Scala 循环控制-3
for循环返回值
- for 循环中的 yield 会把当前的元素记下来,保存在集合中,循环结束后将返回该集合。也称for推导式
val num:Int = 10; //for循环使用yield将具有返回值 var retVal=for ( i: Int <- 1 to num; if i%2==0;if i>5 ) yield i; //增强for遍历数组 for(a<-retVal){ println(a); } //输出6 8 10
十六、练习:使用for循环
需求说明
使用Scala编程输出如图所示加法表

var x=0 var y=6 var z=6 for(i<- 0 to z){println(s”$x+$y=$z”);x=x+1;y=y-1}
//九九乘法表 var i=1 var j=1 for(i<- 1 to 9;j<- 1 to i){print(s”$j*$i=${i*j}\t”);if(i==j)println()}
十七、Scala 数组
存储固定大小的元素
数组索引从0开始
//数组创建方式一 var a1:Array[String] = new Array[String](3) //泛型使用方括号 a1(0)=”Jason” //数组元素访问使用圆括号 a1(1)=”Marie” a1(2)=”Jimmy” //数组创建方式二 var a2=Array(“Jason”,”Marie”,”Jimmy”) //调用Array的伴生对象中的apply()返回Array实例 //数据创建方式三:区间数组 var a3=Array.range(1,10,2) //1-10,步长为2
十八、Scala 元组
可以包含不同类型的元素
最多支持22个元素 (Tuple1~Tuple22)
使用下划线“_”访问元素,“_1″表示第一个元素
//元组声明方式一 var tp1 = (“Mike”, “123 ABC street”, 58) println(tp1._1) println(tp1._2) println(tp1._3) //迭代元组 tp1.productIterator.foreach{ i =>println(“Value = ” + i )} //元组声明方式二 var tp2 = new Tuple3(“Mike”, “123 ABC street”, 58) //元组声明方式三 def mike = “Mike” -> 5 tp1.productIterator.foreach{ i =>println(“Value = ” + i )} //嵌套元祖 def tp3 = “hydra”->6->7 Value=(hydra,6) Value=7 //输出scala.Tuple2 tp3.getClass Class[_ <: ((String, Int), Int)] = class scala.Tuple2 //将元组元素依次赋给三个变量 val(name, address, age) = tp1 println(name) println(address) println(age)
十九、Scala 集合-1
Seq
- 序列,元素按顺序排列
Set
- 集合,元素不重复
Map
- 映射,键值对集合

二十、Scala 集合-2
不可变集合
- scala.collection.immutable,默认Scala选择不可变集合
可变集合:
可以修改、添加或移除一个集合的元素
- scala.collection.mutable
var list2=scala.collection.mutable.ListBuffer(1,2,3) list2(1)=4 list2 //scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 4, 3)


二十一、Scala 集合-3
scala.collection.immutable
Set:ListSet、HashSet、TreeSet
Map:ListMap、HashMap、TreeMap
Seq:Vector、String、Range、List、Stack、Stream、Queue

IndexedSeq:索引序列,通过索引得到高效的随机读取
LinearSeq:线性序列,高效的写入,开头和尾部方便查找
二十二、Scala 集合-4
scala.collection.mutable

常用类:
Buffer – ListBuffer
Map – TreeMap / HashMap
Set – HashSet
二十三、Scala 集合-5
常用集合
名称
|
可变/不可变
|
示例
|
Buffer
|
mutable
|
val buffer = scala.collection.mutable.ArrayBuffer[Int](10, 20, 30);
buffer+=(2,3)
|
Array
|
mutable
|
val arr=Array(1,2,3)
|
List
|
immutable
|
val lst=List(1,2,3)
|
Map
|
mutable
|
val stu= Map(“name” -> “Jason”, “age” -> “18”)
|
Set
|
mutable/immutable
|
val set=Set(1,2,3)
|
Vector
|
immutable
|
val v=Vector(1, 3, 5, 7, 11, 13)
|
Stack
|
mutable/immutable
|
val st=scala.collection.mutable.Stack(1,2,3) //堆栈,先进后出
|
Queue
|
mutable/immutable
|
val q=scala.collection.mutable.Queue(1,2,3) //队列,先进先出
|
BitSet
|
mutable/immutable
|
val bit=scala.collection.mutable.BitSet(3,2,0) //位集合
|
ListMap
|
immutable
|
val map = scala.collection.immutable.ListMap(1->”one”, 2->”two”)
|
HashSet
|
mutable
|
val set= scala.collection.mutable.HashSet(1,2,3)
|
HashMap
|
mutable
|
val stu= scala.collection.mutable.HashMap(“name” -> “Jason”, “age” -> “18”)
|
Jar包位置

二十四、Scala List 常用操作
var c = List[Char](‘a’, ‘b’, ‘c’) var x = ‘x’ +: c // (x, a, b, c) var y = c :+ ‘x’ // (a, b, c, x) import scala.collection.mutable._ var lb = ListBuffer[Int](1, 2, 3, 4) lb += (21, 33) // 88 +=: lb //88, 1, 2, 3, 4, 100, 21, 33 List(77, 66) ++=: lb lb += 100 //1, 2, 3, 4, 100
var l = List[Int](2, 3, 4, 6, 8, 9, 11, 20) var x = l grouped 3 //等价l.grouped(3) x.next() //(2, 3, 4) x.next() //(6, 8, 9) var y = l sliding 2 y.next() // (2, 3) y.next() // (3, 4)
var a1 = Array[Int](1, 2, 3, 4) var a2 = Array[Int](100, 200, 300, 400) var a = List.concat(a1, a2) //Array->List a3=a1++a2 //Arrays->Array a(3) = 333 //Error a3(3)=333 //OK var b = Array(333, “333”, ‘3’, false ) var c = List.concat(a, b) val x = a.filter( _ %2 != 0 ) val y = a.reverse var m = a.groupBy(t => t%2 == 0) var n = a.slice(2, 4) a.sorted //1, 2, 3, 4, 100, 200, 300, 400 a.sorted( Ordering.Int.reverse ) a.sortWith( _ > _ ) a.sortBy( x => x ) //升序 a.sortBy( x => x*(-1) ) //降序
练习
var c = List(‘a’,’b’,’c’) //创建List类型集合 ‘x’+:c //添加元素(不可变) c=’x’+:c //开头添加元素(可变,重新赋值) var b=’z’+:c //添加元素并赋值给其他集合 c=c:+’d’ //队尾添加元素 import scala.collection.mutable._ //为ListBuffer导入可变集合包 val 1b = ListBuffer(1,2,3,4) //创建ListBuffer集合 lb+=100 //队尾添加元素 lb+=(22,33) //队尾添加多个元素 90+=:lb //开头添加元素 List(55,66)++=:lb //开头添加一个List集合 var lb2=List(1,2,3,4,5,6,7,8) //创建一个List集合 var iter=lb2 grouped 3 //为集合分3组,生成迭代器 iter.next() //输出迭代器下一组的值 var iter2=lb2.sliding(2) //为集合生成另一个迭代器,滑动长度默认为1 var iter3=lb2.sliding(2,2) //为集合生成另一个迭代器,长度为2,滑动为2 var a=Array(1,2,3,4) //创建集合a var b=Array(5,6,7,8) //创建集合b var c=List.concat(a,b) //合并2个Array,并转集合类型为List var aa=a++b //合并2个Array成另一个Array aa(3)=111 //修改aa第4个元素的值 var b=Array(333,”333″,’3′,false) //创建一个多元素类型的Array var c=List.concat(a,b) //合并2个多元素集合为List lb2.filter(x=>x%2!=0) //过滤器,过滤掉2的倍数 lb2.filter(_!=5) //过滤掉5,(下划线等于x=>x) var a = Array(10,1,2,3,4,5,6,7,8) //创建一个int集合 a.reverse //倒序排列 a.sorted //正序排列 a.sorted(Ordering.Int.reverse) //传入新参数后,倒序排列 a.sortWith(_>_) //简版降序 a.sortWith(_<_) //简版升序 a.sortBy(x=>x) //升序 a.sortBy(x=>x*(-1)) //降序 var m = a.groupBy(t=>t%2==0) //以偶数分组 //Map(false -> Array(1, 3, 5, 7), true -> Array(10, 2, 4, 6, 8)) var n=a.slice(0,7) //切割集合,从下标0到元素值7
二十五、Scala Set 常用操作
var s = Set(“ab”, “yz”) s += “mn” //mn, ab, yz s += “mn” //?? s -= “yz” //mn, ab var t = Set(“ab”, “gh”, “mn”, “st”, “yz” ) t — s //gh, st, yz t ++ s //ab, gh, mn, st, ya\ var s = Set(“ab”, “yz”) var t = Set(“ab”, “gh”, “mn”, “st”, “yz” )
可变Set
import scala.collection.mutable._ val s1=scala.collection.mutable.Set(“ab”,”yz”) s1 += “mn //TreeSet var os = SortedSet(1,99,66,54,77) os +=33
练习
var s = Set(1,2,4) //创建一个Set集合,不可变 s+1 //不可添加重复元素 s+5 //队尾添加元素(不可变) s=s+5 //队尾添加元素(可变,重新赋值) var s2=(1,2,4,5,6) //创建第二个集合 s & s2 //交集 s intersect s2 //交集(并排序) s|s2 //并集 s union s2 //并集 s++s2 //并集 s2 &~ s //差集(大放前) s2 diff s //差集(大放前) s2–s //差集(大放前)
二十六、Scala Map 常用操作
var m = Map[String, Int](“a”->1, “b”->2, “c”->3, “d”->4, “e”->5, “f”->6, “g”->7, “h”->8, “i”->9) m(“a”) //通过key寻找value m.keys //获取所有key m.values //获取所有value m.getOrElse(“z”,0) //如果有z,返回value,没有就返回0 m += (“j”->11) //给集合增加一对键值 m += (“j”->12) //同样的key,会覆盖前一个值 for((k,v)<-m){println(k+”:”+v)} //遍历map集合 //创建一个自动key排序的map val m2 = scala.collection.SortedMap(“dd”->25,”cc”->30,”aa”->28,”bb”->29) //创建一个可变的map val m3 = scala.collection.mutable.Map(“dd”->25,”cc”->30,”aa”->28,”bb”->29) var n = m ++ Map[String, Int](“a”->3, “j”->99) //重新赋值,并生成新的集合 n -= (“g”, “e”) //去除一对键值
二十七、Scala Stream & Vector
Stream是List惰性版
它只确定第一个值,后面的值用到的时候,再求值,可以防止数据过大,全部加载导致OOM
val stream = (1 to 1000).toStream stream //查看集合,默认只显示第一个 stream.head //查看第1个值 stream.tail //从1个值开始,输出,默认到下一个 stream(3) //查看第4个值 stream.tail //从1个值开始,输出到上一步求的值
Vector(索引序列)拥有连续的内存空间,利于随机存取(直接访问)
val v = Vector.empty :+ 2 :+ 2 val v1 = v ++ Vector[Int](3) //在v的基础上,队尾增加一个3 v.length //集合长度(int类型) v1.length //集合长度(int类型) val x = IndexedSeq(1,2,3)
二十八、练习2:列表分组排序
需求说明
- 请将下列同学分为2组,依次每3人一组,组内按名排序
- “Jason,Vince,Dwan,Lynn,Stephon”

var a=List(“Dwan”,”Jason”,”Vince”) var b=List(“Lynn”,”Stephon”) var c=List.concat(a,b) c=c.sorted
二十九、Null 等其他数据和类型
Null
|
一个数据类型,继承自AnyRef(集合)
|
null
|
表示一个空值
|
Nothing
|
Nothing是所有类型的子类型,没有Nothing的实例,啥也不是
|
Nil
|
定义集合空的初始值,继承自List[Nothing]
|
None
|
继承自Option[Nothing]
|
Option
|
可能有值[Some(T)],可能没有值[None]
|
Try
|
Success或者Failure,要么成功要么失败
|
Left & Right
|
Either的子类。当返回值可能有2种类型的时候,做判断,要么a,要么b
|

Null & null
def a(thing:Null):Unit={ println(“ok”) } val b:Null=null val c:String=null a(b) //通过,b即Null类型 a(c) //报错,c是null空值,但还属于String类型 a(null) //通过,null自身是Null类型
Nothing
val emptyIntList:List[Int]=List[Nothing]() //nothing可以是Int类型 val emptyStringList:List[String]=List[Nothing]() //nothing可以是String类型 val emptyStringList:List[String]=List[Nothing](“abc”) //String不是nothing //任何空的集合必定是空的
Option
val s:Option[String] = None s == Node //true s.getOrElse(“wu”) //String = wu val o:Option[Int] = scala.util.Try(“123i”.toInt).toOption o == None //Boolean = true val o:Option[Int] = scala.util.Try(“123”.toInt).toOption o.get //Int = 123 def getAStringMaybe(num:Int):Option[String]={ if(num>=0) Some(“A positive number!”) else None //A number less than 0? Impossible! } getAStringMaybe:{num:Int}Option[String] getAStringMaybe(-1) //Option[String] = None getAStringMaybe(2) //Option[String] = Some(A positive number!)
Left & Right
def divideBy(x:Int,y:Int):Either[String,Int]=if(y==0) Left(“Dude,can’t divide by 0”) else Right(x/y) divideBy(100,2) match{ case Left(a) => println(a) case Right(b) => print(“right=%d”.format(b)) } //right=50
Try
import scala.util.Success import scala.util.Failure import scala.util.Try Try(“124”.toInt) match{ case Success(a) => println(“the value is %d”.format(a)) case Failure(e) => println(“Exception occurred – %s”.format(e.getMessage)) } //Yes Try(“hi”.toInt) match{ case Success(a) => println(“the value is %d”.format(a)) case Failure(e) => println(“Exception occurred – %s”.format(e.getMessage)) } //No
三十、Scala 字符串格式化
“%1$s-%2$s-%3$s”.format(“spark”,”scala”,”ml”) “%08.3f”.format(11.56789) “%d%%”.format(86)
数据类型到字符串的转换
转换符
|
说明
|
示例
|
%s
|
字符串类型
|
“wwx”
|
%c
|
字符类型
|
‘w’
|
%b
|
布尔类型
|
true
|
%d
|
整数类型(十进制)
|
99
|
%x
|
整数类型(十六进制)
|
FF
|
%o
|
整数类型(八进制)
|
77
|
%f
|
浮点类型
|
99.99
|
%a
|
十六进制浮点类型
|
FF.35AE
|
%e
|
指数类型
|
9.668e+5
|
%g
|
通用浮点类型(f和e类型中较短的)
|
|
%h
|
散列码
|
|
%%
|
百分比类型
|
%
|
%n
|
换行符
|
|
%tx
|
日期与时间类型(x代表不同的日期与时间转换符
|
搭配转换符的标志
标志
|
说明
|
示例
|
结果
|
+
|
为正数或者负数添加符号
|
(“%+d”,112)
|
+112
|
−
|
左对齐
|
(“%-5d”,112)
|
|112 |
|
0
|
数字前面补0
|
(“%05d”, 99)
|
00099
|
空格
|
在整数之前添加指定数量的空格
|
(“% 5d”, 99)
|
| 99|
|
,
|
以“,”对数字分组
|
(“%,f”, 9999.99)
|
9,999.990000
|
(
|
使用括号包含负数
|
(“%(f”, -99.99)
|
(99.990000)
|
#
|
如果是浮点数则包含小数点,如果是16进制或8进制则添加0x或0
|
(“%#x”, 99)
(“%#o”, 99)
|
0x63
0143
|
<
|
格式化前一个转换符所描述的参数
|
(“%f和%<3.2f”, 99.45)
|
99.450000和99.45
|
$
|
被格式化的参数索引
|
(“%1d,s”, 89,”abc”)
|
89,abc
|