1. Scala概述
- 为什么学习scala
-
Spark—新一代内存级大数据计算框架,是大数据的重要内容。
-
Spark就是使用Scala编写的。因此为了更好的学习Spark, 需要掌握Scala这门语言。
-
Scala 是 Scalable Language 的简写,是一门多范式(范式/编程方式[面向对象/函数式编程])的编程语言
-
联邦理工学院洛桑(EPFL)的Martin Odersky于2001年开始设计Scala
-
Spark的兴起,带动Scala语言的发展!
- Scala语言诞生小故事
- 创始人马丁·奥德斯基(Martin Odersky)是编译器及编程的狂热爱好者,长时间的编程之后,希望发明一种语言,能够让写程序这样的基础工作变得高效,简单。所以当接触到JAVA语言后,对JAVA这门便携式,运行在网络,且存在垃圾回收的语言产生了极大的兴趣,所以决定将函数式编程语言的特点融合到JAVA中,由此发明了两种语言(Pizza & Scala) 递归。
- Pizza和Scala极大地推动了Java编程语言的发展。[如何理解?]
jdk5.0 的泛型,for循环增强, 自动类型转换等,都是从Pizza 引入的新特性。
jdk8.0 的类型推断,Lambda表达式就是从scala引入的特性。
且现在主流JVM的javac编译器就是马丁·奥德斯基编写出来的。Jdk5.0 Jdk8.0的编译器就是马丁·奥德斯基写的,因此马丁·奥德斯基 一个人的战斗力抵得上一个Java开发团队。
- Scala 和 Java 以及 jvm 的关系分析图
一般来说,学Scala的人,都会Java,而Scala
是基于Java的,因此我们需要将Scala和Java以及JVM 之间
的关系搞清楚,否则学习Scala你会蒙圈。
- java 代码编译运行示意图
- scala特点:
- scala对一些java进行了包装,继承了java的一些类或者接口
2. Scala语言特点
加了分号也不会报错,但是多余。
- Scala是一门以java虚拟机(JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起
的静态类型编程语言。
-
Scala 是一门多范式 (multi-paradigm) 的编程语言,Scala支持面向对象和函数式编程
-
Scala源代码(.scala)会被编译成Java字节码(.class),然后运行于JVM之上,并可以调用现有的Java类库,实现两种语言的无缝对接。
-
scala 单作为一门语言来看, 非常的简洁高效 (三元运算, ++ , --)
-
Scala 在设计时,马丁·奥德斯基 是参考了Java的设计思想,可以说Scala是源于java,同时马丁·奥德斯基 也加入了自己的思想,将函数式编程语言的特点融合到JAVA中, 因此,对于学习过Java的同学,只要在学习Scala的过程中,搞清楚Scala 和 java相同点和不同点,就可以快速的掌握Scala这门语言
-
快速有效掌握Scala的建议 [1. 学习scala 特有的语法 2. 搞清楚 scala 和java 区别 3. 如何规范的使用scala]
3. Windows搭建Scala开发环境
Scala SDK下载:
链接:https://pan.baidu.com/s/11obm7JclgjcFJE24vJ_JVg
提取码:hb1s
- 安装&配置
-
Scala需要Java运行时库,安装Scala需要首先安装JVM虚拟机并配置好,推荐安装JDK1.8
-
在http://www.scala-lang.org/ 下载Scala2.11.8程序安装包
-
配置Jdk的环境变量
-
配置SCALA_HOMESCALA_HOME= D:\program\scala-2.11.8
-
将Scala安装目录下的bin目录加入到PATH环境变量在PATH变量中添加:%SCALA_HOME%\bin
-
在终端中输入“scala”命令打开scala解释器
4. Linux下搭建Scala开发环境
scala sdk下载
链接:https://pan.baidu.com/s/1lUTzYIxc-atpzBa9RJbCdg
提取码:iid3
- Linux下安装Scala和Windows下安装类似,步骤如下:
首先访问下载链接:http://www.scala-lang.org/download/默认这里下载的是Windows版本,这时点击上面的All downloads进入所有的版本下载页面:
然后选择最新版本,Scala 2.11.8进入
进入后拉到页面下方,选择Mac OSX,Unix版本的二进制包下载即可
下载之后,上传至服务器,准备安装
首先建立scala存放目录:
mkdir /usr/local/scala
然后释放scala并安装至指定目录:
tar -xvzf scala-2.11.8.tgz && mv scala-2.11.8 /usr/local/scala/
然后配置环境变量,执行 vi /etc/profile
编辑配置文件,在PATH后追加scala的二进制位置,这里是: :/usr/local/scala/scala-2.11.8/bin
配置完之后,保存并退出
执行 source /etc/profile
使环境变量生效
执行 scala -version
正常返回版本信息,则Scala环境配置成功
5.IDEA安装Scala插件
- 默认情况下IDEA不支持Scala的开发,需要安装Scala插件
Scala插件下载:
链接:https://pan.baidu.com/s/1BWpxNP6FPkkFsxI1i745kw
提取码:axff
配置IDEA
-
打开IDEA工具,如图:点击Configure
或者: 文件->settings->pulgins 这里也能找到插件安装的位置 -
点击Plugins
-
点击Install plugin from disk
-
选择scala的plugins
为了方便可以拷贝scala的plugins到scala的安装目录下。
-
此时会显示一个Scala的条目,在右侧点击Restart IntelliJ IDEA
-
重新启动后,IDEA才能加载scala的插件,此时Scala的插件安装成功了
-
添加Scala SDK
6.Scala快速入门
7.Idea开发Scala项目
object ScalaDemo {
def main(args: Array[String]): Unit = {
println("hello,scala, idea...")
var num1: Int = 10
var num2: Int = 20
println(num1 + num2)
println("名字\t年龄\t邮件\t性别")
}
}
Scala执行流程分析
- 示意图
Scala程序开发注意事项(重点)
- Scala源文件以 “.scala" 为扩展名。
- Scala程序的执行入口是main()函数。
- Scala语言严格区分大小写。
- Scala方法由一条条语句构成,每个语句后不需要分号(Scala语言会在每行后自动加分号),这也体现出Scala的简洁性。
- 如果在同一行有多条语句,除了最后一条语句不需要分号,其它语句需要分号。
Scala语言转义字符
- Scala常用的转义字符(escape char)
var num1: Int = 10
var num2: Int = 20
println(num1 + num2)
println("名字\t年龄\t邮件\t性别")
8.字符串输出3种方式
字符串通过+号连接(类似java)。
printf用法 (类似C语言)字符串通过 % 传值。
字符串通过$引用(类似PHP)
object printDemo {
def main(args: Array[String]): Unit = {
var str1: String = "hello"
var str2: String = " world!"
println(str1 + str2)
var name:String = "tom"
var age:Int = 10
var sal:Float = 10.67f
var height:Double = 180.15
//格式化输出
printf("名字=%s 年龄是%d 薪水%.2f 高%.3f",name,age,sal,height)
//scala支持使用$输出内容, 编译器会去解析$对应变量
println(s"\n个人信息如下:\n 名字$name \n年龄$age \n薪水$sal ")
//如果下字符串中出现了类似${age + 10} 则表示{}是一个表达式
println(s"\n个人信息如下2:\n 名字${name} \n年龄${age + 10} \n薪水${sal * 100} ")
}
}
9. 关联Scala源码
scala 源码下载:
链接:https://pan.baidu.com/s/11NPEzYREqbZw7tRRJrfO7w
提取码:zd51
- 在使用scala过程中,为了搞清楚scala底层的机制,需要查看源码,下面看看如果关联和查看Scala的源码包
- 查看源码, 选择要查看的方法或者类, 输入 ctrl + b
- 关联源码
- 为了方便,先将源码的放到scala安装文件夹的lib目录下
- 选择刚才解压的源码文件夹
- 加载完成后会自动跳到源码
10.文档注释
- 注释(comment)
介绍:
用于注解说明解释程序的文字就是注释,注释提高了代码的阅读性;
注释是一个程序员必须要具有的良好编程习惯。将自己的思想通过注释先整理出来,再用代码去体现。
- Scala中的注释类型
- 单行注释
- 多行注释
- 文档注释
object Comment {
def main(args: Array[String]): Unit = {
println("hello,world!")
}
//tab 或者是 tab+shift
/**
* @deprecated 过期
* @example
* 输入n1 = 10 n2 = 20 return 30
* @param n1
* @param n2
* @return 和
*/
def sum(n1: Int, n2: Int): Int = {
return n1 + n2
}
}
- 找到文件所在位置
- cmd到这个目录
- 使用命令生成文档注释
scaladoc -d f:/mydoc Comment.scala
打开生成的index.heml文件
11.编写规则 注意事项和手册
Scala官方编程指南
12.Scala变量的基本使用
object VarDemo01 {
def main(args: Array[String]): Unit = {
//编译器,动态的 (逃逸分析)
var age: Int = 10
var sal: Double = 10.9
var name:String = "tom"
var isPass:Boolean = true
//在scala中,小数默认为Double ,整数默认为Int
var score:Float = 70.9f
println(s"${age} ${isPass}")
}
}
13.Scala变量的注意事项
- 声明变量时,类型可以省略(编译器自动推导,即类型推导),变量声明时,需要初始值
声明时就必须赋值,
//类型推导
var num = 10 // 这时num就是Int
//方式1 , 可以利用idea的提示来证明,给出提示
//方式2, 使用isInstanceOf[Int]判断
println(num.isInstanceOf[Int]) //输出true
- 类型确定后,就不能修改,说明Scala 是强数据类型语言.
//类型确定后,就不能修改,说明Scala 是强数据类型语言()
// num = 2.3, 错误
- 在声明/定义一个变量时,可以使用var 或者 val 来修饰, var 修饰的变量可改变,val 修饰的变量不可改
反编译的结果
反编译工具下载
链接:https://pan.baidu.com/s/1cK8ukUHmuTmcAYGFANUpjQ
提取码:371b
- cscala设计者为什么设计 var 和 val
(1) 在实际编程,我们更多的需求是获取/创建一个对象后,读取该对象的属性,或者是修改对象的属性值, 但是我们很少去改变这个对象本身这时,我们就可以使用val
(2) 因为val 没有线程安全问题,因此效率高,scala的设计者推荐我们val
(3) 如果对象需要改变,则使用var
var age = 10 //即age 是可以改变的.
age = 30 // ok
val num2 = 30
//因为dog是val修饰的所以dog不能改变
//num2 = 40 // val 修饰的变量是不可以改变.
val dog = new Dog
//dog = new Dog //Reassignment to val
//因为Dog类成员属相age和name是var修饰的可以改变
dog.age = 90 //ok
//因为Dog类成员属相name是val修饰的不可以改变
//dog.name = "小花" //error
class Dog {
//声明一个age属性,给了一个默认值 _
var age :Int = 0 //
//声明名字
val name:String = "" //
}
- 程序中 +号的使用
- 当左右两边都是数值型时,则做加法运算
- 当左右两边有一方为字符串,则做拼接运算
14.Scala数据类型的一览图
- Scala 与 Java有着相同的数据类型,在Scala中数据类型都是对象,也就是说scala没有java中的原生类型
- scala中一切都是对象,是一个纯面向对象的开发语言:例如数据100也是对象也有自己方法,bool性也是对象
object TypeDemo01 {
def main(args: Array[String]): Unit = {
var num1: Int = 10
//因为Int 是一个类,因此他的一个实例,就是可以使用很多方法
//scala中一切都是对象,是一个纯面向对象的开发语言:例如数据100也是对象也有自己方法,bool性也是对象
println(num1.toDouble + "\t" +num1.toString + 100.toDouble)
var isPass = true
println(isPass.toString)
//在scala中,如果一个方法,没有形参,则可以省略()
sayHi
sayHi()
}
def sayHi(): Unit = {
println("say hi")
}
}
- Scala数据类型分为两大类 AnyVal(值类型) 和 AnyRef(引用类型), 注意:不管是AnyVal还是AnyRef 都是对象。
- Scala数据类型的一览图
Nothing类最底层的类,是所有类的子类与java的Object类相反, object类是java所有的父类
object TypeDemo02 {
def main(args: Array[String]): Unit = {
println(sayHello)
}
//比如开发中,我们有一个方法,就会异常中断,这时就可以返回Nothing
//即当我们Nothing做返回值,就是明确说明该方法没有没有正常返回值
def sayHello: Nothing = {
throw new Exception("抛出异常")
}
}
var num = 1.2 //默认为double
var num2 = 1.7f //这是float
//double直接复制给float是不对的
//num2 = num //error
//修改。使用对象方法转换
num2 = num.toFloat
- 相对于java的类型系统,scala要复杂些!也正是这复杂多变的类型系统才让面向对象编程和函数式编程完美的融合在了一起
15.Scala数据类型
- Scala数据类型表
1.Scala整型
- 整型的类型
Scala的整数类型就是用于存放整数值的,比如 12 , 30, 3456等等
- 整型的使用细节
- Scala各整数类型有固定的表数范围和字段长度,不受具体OS的影响,以保证Scala程序的可移植性。
- Scala的整型 常量/字面量 默认为 Int 型,声明Long型 常量/字面量 须后加‘l’’或‘L’ [反编译看]
- Scala程序中变量常声明为Int型,除非不足以表示大数,才使用Long
2.Scala浮点型
Scala的浮点类型可以表示一个小数,比如 123.4f,7.8 ,0.12等等
- 浮点型的分类
- 浮点型使用细节
- 与整数类型类似,Scala 浮点类型也有固定的表数范围和字段长度,不受具体OS的影响。
- Scala的浮点型常量默认为Double型,声明Float型常量,须后加‘f’或‘F’。
- 浮点型常量有两种表示形式
十进制数形式:如:5.12 512.0f .512 (必须有小数点)
科学计数法形式:如:5.12e2 = 5.12乘以10的2次方 5.12E-2 = 5.12除以10的2次方 - 通常情况下,应该使用Double型,因为它比Float型更精确(小数点后大致7位) //测试数据 :2.2345678912f , 2.2345678912
3.Scala字符类型
字符类型可以表示单个字符,字符类型是Char, 16位无符号Unicode字符(2个字节), 区间值为 U+0000 到 U+FFFF
- 字符类型(Char)
字符类型使用细节
-
字符常量是用单引号(‘ ’)括起来的单个字符。例如:var c1 = 'a‘ var c2 = '中‘ var c3 = ‘9’
-
Scala 也允许使用转义字符‘\’来将其后的字符转变为特殊字符型常量。例如:var c3 = ‘\n’ // '\n’表示换行符
3)可以直接给Char赋一个整数,然后输出时,会按照对应的unicode 码字符输出 [’\u0061’ 97] ,unicode码值表包含ASCII码
//当我们输出一个char类型是整数,他会输出该数字对应的字符(码值表 unicode)//unicode 码值表包括ascii
var char1: Char = 97
println("char1=" + char1) // a
4) Char类型是可以进行运算的,相当于一个整数,因为它都对应有Unicode码.
//char 可以当做数字进行运行
var char2: Char = 'a'
var num = 10 + char2
println("num=" + num) // 107
注意:
)
//原因和分析
//1. 当把一个计算的结果赋值一个变量,则编译器会进行类型转换及判断(即会看范围+类型)
// var c2: Char = 'a' + 1 //错误 int->Char
// var c3: Char = 97 + 1 //错误 int->Char
//2. 当把一个字面量赋值一个变量,则编译器会进行范围的判定
var c4: Char = 98 //则编译器不会进行类型转换及判断,只行范围的判定
4.布尔类型Boolean
- 布尔类型也叫Boolean类型,Booolean类型数据只允许取值true和false
- boolean类型占1个字节。
- boolean 类型适于逻辑运算,一般用于程序流程控制[后面详解]:
布尔类型主要用在:
- if条件控制语句;
- while循环控制语句;
- do-while循环控制语句;
- for循环控制语句
5.Null Nothing Unit
Unit类型、Null类型和Nothing类型,基本说明:
使用细节和注意事项:
-
1.Null类只有一个实例对象,null,类似于Java中的null引用。null可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型(AnyVal: 比如 Int, Float, Char, Boolean, Long, Double, Byte, Short)
-
2.Unit类型用来标识过程,也就是没有明确返回值的函数。由此可见,Unit类似于Java里的void。Unit只有一个实例,(),这个实例也没有实质的意义
-
3.Nothing,可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返回,而且由于Nothing是其他任意类型的子类,他还能跟要求返回值的方法兼容。
实例:
- Unit类型
val res = sayHello()
println("res=" + res)
//Unit等价于java的void,只有一个实例值()
def sayHello(): Unit = {
}
- Null类型
//null可以赋值给任意引用类型(AnyRef)
val dog: Dog = null //正确
//null 不能赋值给值类型(AnyVal: 比如 Int, Float, Char, Boolean, Long, Double, Byte, Short)
val char1: Char = null //错误
温故知新
6.值类型的自动转换
7.值类型的强制转换
8.值类型与String相互转换
9.标识符的使用说明
16.运算符
1.算术运算符(27:28)
2.关系运算符(03:43)
3.逻辑运算符(02:31)
4.赋值运算符(13:29)
5.运算符特别说明(07:33)
6.运算符优先级(05:34)
17.程序流程控制
从控制台输入内容
顺序控制
顺序控制介绍
程序从上到下逐行地执行,中间没有任何判断和跳转。
顺序控制举例和注意事项
Scala中定义变量时采用合法的前向引用。如:
def main(args : Array[String]) : Unit = {
var num1 = 12
var num2 = num1 + 2
}
错误形式:
def main(args : Array[String]) : Unit = {
var num2 = num1 + 2
var num1 = 12
}
注意:方法可以在定义在后,使用在前
单分支
双分支
多分支
分支控制注意事项
嵌套分支
17.1. for循环
for循环的两种方式
基本介绍
- Scala 也为for 循环这一常见的控制结构提供了非常多的特性,这些for 循环的特性被称为:
for 推导式(for comprehension)或for 表达式(for expression)
//输出10句 "hello,尚硅谷!"
val start = 1
val end = 10
//说明
//1. start 从哪个数开始循环
//2. to 是关键字
//3. end 循环结束的值
//4. start to end 表示前后闭合
for (i <- start to end) {
println("你好,尚硅谷" + i)
}
//说明for 这种推导时,也可以直接对集合进行遍历
var list = List("hello", 10, 30, "tom")
for (item <- list) {
println("item=" + item)
}
for循环守卫
跳过,不是跳出
引入变量
for(i <- 1 to 3; j = 4 - i) {
print(j + " ") // 3,2,1
}
嵌套循环(多层循环)
for(i <- 1 to 3; j <- 1 to 3) {
println(" i =" + i + " j = " + j) //输出即句 9
}
//上面的写法,可以写成
println("--------------------------")
for(i <- 1 to 3) {
for (j <- 1 to 3) {
println(" i =" + i + " j = " + j) //输出即句 9
}
}
循环返回值
object yieldFor {
def main(args: Array[String]): Unit = {
//说明 val res = for(i <- 1 to 10) yield i 含义
//1. 对1 to 10 进行遍历
//2. yield i 将每次循环得到i 放入到集合Vector中,并返回给res
//3. i 这里是一个代码块,这就意味我们可以对i进行处理
//4. 下面的这个方式,就体现出scala一个重要的语法特点,就是将一个集合中个各个数据
// 进行处理,并返回给新的集合
val res = for(i <- 1 to 10) yield {
if (i % 2 == 0) {
i
}else {
"不是偶数"
}
}
println(res)
}
}
使用花括号{}代替小括号()
object usefor2 {
def main(args: Array[String]): Unit = {
for (i <- 1 to 3; j = i * 2) {
println(" i= " + i + " j= " + j)
}
//等价
println("------------------------")
for {
i <- 1 to 3
j = i * 2} {
println(" i= " + i + " j= " + j)
}
}
}
- 注意事项和细节说明
- scala 的for循环形式和java是较大差异,这点请同学们注意,但是基本的原理还是一样的。
- scala 的for循环的步长如何控制! [for(i <- Range(1,3,2)]
- 思考题:如何使用循环守卫控制步长
object stepfor {
def main(args: Array[String]): Unit = {
for (i <- 1 to 10) {
println("i=" + i)
}
//步长控制为2
println("-------------")
//Range(1,10,2)的对应的构建方法是
//def apply(start: Int, end: Int, step: Int): Range = new Range(start, end, step)
for (i <- Range(1, 10, 2)) {
println("i=" + i)
}
//控制步长的第二种方式-for循环守卫
println("**************************")
for (i <- 1 to 10 if i % 2 == 1) {
println("i=" + i)
}
}
}
17.2. while循环控制
While循环
- while循环在scala中不推荐使用,推荐使用for,因为while会用到while外部的变量
object WhileDemo01 {
def main(args: Array[String]): Unit = {
//输出10句 hello,尚硅谷
//1. 定义循环变量
var i = 0
//2. i < 10 条件
while (i < 10){
println("hello,尚硅谷" + i) //循环体
//循环变量迭代
i += 1
}
}
}
do while循环
object Demo01 {
def main(args: Array[String]): Unit = {
var i = 0 // for
do {
printf(i + "hello,尚硅谷\n" )
i += 1
} while (i < 10)
}
}
多重循环应用案例(27:41)免费
while循环的中断
scala内置控制结构特地去掉了break和coutinue, 是为了更好的适应函数式编程,推荐使用函数式风格解决break和contine的功能,而不是用关键字。
- 实现Break和Continue
import util.control.Breaks._
object WhileBreak {
def main(args: Array[String]): Unit = {
var n = 1
//breakable()函数
//说明
//1. breakable 是一个高阶函数:可以接收函数的函数就是高阶函数(后面详解)
//2. def breakable(op: => Unit) {
// try {
// op
// } catch {
// case ex: BreakControl =>
// if (ex ne breakException) throw ex
// }
// }
// (1) op: => Unit 表示接收的参数是一个没有输入,也没有返回值的函数
// (2) 即可以简单理解可以接收一段代码块
// 3. breakable 对break()抛出的异常做了处理,代码就继续执行
// 4. 当我们传入的是代码块,scala程序员会将() 改成{}
breakable {
while (n <= 20) {
n += 1
println("n=" + n)
if (n == 18) {
//中断while
//说明
//1. 在scala中使用函数式的break函数中断循环
//2. def break(): Nothing = { throw breakException }
break()
}
}
}
println("ok~~")
//注意break函数,可以使用在for或者do..while
breakable {
for (i <- 1 to 100) {
println("i=" + i)
if (i == 20) {
break()
}
}
}
println("ok2~~~~")
}
}
18.函数式编程
18.1函数式编程基本介绍
函数式编程介绍
18.2.函数式编程几个重要概念
在学习Scala中将方法、函数、函数式编程和面向对象编程关系分析图
- “函数式编程"是一种"编程范式”(programming paradigm)。
- 它属于"结构化编程"的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用。
- 函数式编程中,将函数也当做数据类型,因此可以接受函数当作输入(参数)和输出(返回值)。
- 函数式编程中,最重要的就是函数。
18.3 函数的必要性及学习方法
18.4 函数基本介绍和快速入门
- 函数定义:
object FunDemo01 {
def main(args: Array[String]): Unit = {
val n1 = 10
val n2 = 20
println("res=" + getRes(1, 2, '+'))
}
//定义函数/方法
def getRes(n1: Int, n2: Int, oper: Char) = {
if (oper == '+') {
n1 + n2 //返回 return n1+n2 没有return默认返回程序执行最后一行的结果
} else if (oper == '-') {
n1 - n2
} else {
//返回null
null
}
}
}
18.5 函数(方法)的调用机制
- 函数-调用过程
18.6 函数递归调用的机制
函数递归的课堂练习(
函数使用注意事项和细节1(34:30)免费
函数使用注意事项和细节2(04:28)免费
函数使用注意事项和细节3(12:35)免费