scala的基本语法
2.1 注释
对于scala的注释,简而言之就是一句话,和java的注释一模一样
基本语法 (1)单行注释:// (2)多行注释:/* */ (3)文档注释:/** * */ |
代码示例:
Scala package com.doitedu.demo01 object TestNotes { def main(args: Array[String]): Unit = { //(1)单行注释:// println("涛哥") //(2)多行注释:/* */ /* println("涛哥") println("行哥") */ //(3)文档注释: /** * */ /** * println("乃哥") * println("雨哥") * println("行哥") */ } } |
2.2 变量和常量(重点)
Java // 回顾:Java 变量和常量语法 // 变量类型 变量名称 = 初始值 int a = 10 // final 常量类型 常量名称 = 初始值 final int b = 20 |
scala定义变量常量的基本语法
Scala // var 变量名 [: 变量类型] = 初始值 var i:Int = 10 variable :可变的 // val 常量名 [: 常量类型] = 初始值 val j:Int = 20 value :值
var variable 可变的 代表声明变量
val value 值 代表声明常量 |
注意:
- val 在编程的过程中我们大部分的操作是获取值或者是获取一个创建好的对象,然后操作对象中的属性,很少改变这个对象变量
- 优先使用val ,但是当变量后续的需要变化的时候使用var
|
练一练:
- 声明变量时,类型可以省略,编译器自动推导,即类型推导
- 类型确定后,就不能修改,说明 Scala 是强数据类型语言。
- 变量声明时,必须要有初始值
- 在声明/定义一个变量时,可以使用 var 或者 val 来修饰,var 修饰的变量可改变,val修饰的变量不可改。
- var 修饰的对象引用可以改变,val 修饰的对象则不可改变,但对象的状态(值)却是可以改变的。(比如:自定义对象、数组、集合等等)
Scala package com.doitedu.demo02 object TestVar { def main(args: Array[String]): Unit = { //(1)声明变量时,类型可以省略,编译器自动推导,即类型推导 var age = 18 age = 30 //(2)类型确定后,就不能修改,说明 Scala 是强数据类型语言。 // age = "zhangsan" // 错误 //(3)变量声明时,必须要有初始值 // var name //错误 //(4)在声明/定义一个变量时,可以使用 var 或者 val 来修饰,var 修饰的变量可改变,val 修饰的变量不可改。 var num1 = 10 // 可变 val num2 = 20 // 不可变 num1 = 30 // 正确 //num2 = 100 //错误,因为 num2 是 val 修饰的 } } |
Scala object demo03{ def main(args: Array[String]): Unit = { // p1 是 var 修饰的,p1 的属性可以变,而且 p1 本身也可以变 var p1 = new Person() p1.name = "zhangsan" p1 = null // p2 是 val 修饰的,那么 p2 本身就不可变(即 p2 的内存地址不能变), 但是,p2 的属性是可以变,因为属性并没有用 val 修饰。 val p2 = new Person() p2.name="jinlian" // p2 = null // 错误的,因为 p2 是 val 修饰的 } } class Person{ var name : String = "jinlian" } |
练一练:
多易现在开售了一个小课堂来卖课(小型的电商平台): 对于销售这块而言,我们是不是要存在一些属性字段: 店铺名称:多易教育 课程名称:java基础,mysql,hadoop..... 讲课老师:源哥,涛哥,星哥,行哥 课程的价格:199,299,399,99 红包类型: 首次购买红包,老学员红包 红包金额:9.9 18.8 活动名称:老用户再次购买,新用户首次购买,学员推荐购买 活动类型:6.18 10.24 11.11 活动折扣力度:9折 5折 8.8折 购买用户用户名:zhangsan,lisi 用户手机号:18860875775,18860875776 用户现在的职位:etl工程师,大数据开发工程师,数仓工程师 用户的邮箱:email 订单号:111122223333 订单金额:398 |
代码:
Scala package com.doitedu
object demo01{
/** * 店铺名称:多易教育 * 课程名称:java基础,mysql,hadoop..... * 讲课老师:源哥,涛哥,星哥,行哥 * 课程的价格:199,299,399,99 * 红包类型: 首次购买红包,老学员红包 * 红包金额:9.9 18.8 * 活动名称:老用户再次购买,新用户首次购买,学员推荐购买 * 活动类型:6.18 10.24 11.11 * 活动折扣力度:9折 5折 8.8折 * 购买用户用户名:姜海涛,江一 * 用户手机号:18860875775,1886087,5776 * 用户现在的职位:etl工程师,大数据开发工程师,数仓工程师 * 用户的邮箱:email * 订单号:111122223333 * 订单金额:119.4 */ def main(args: Array[String]): Unit = { //店铺名称:多易教育 val shopName = "多易教育" //课程名称:java基础,mysql,hadoop..... val subjectName = "java基础" //讲课老师:源哥,涛哥,星哥,行哥 val tName = "涛哥" //课程的价格:199,299,399,99 val subjectPrice = 199.00 //红包类型: 首次购买红包,老学员红包 val bonusType = "new" //红包金额 val bonus = 9.9 //活动名称 val activeName = "老用户再次购买" //活动类型:6.18 10.24 11.11 val activeType = "程序员节" //活动折扣力度 val activeDiscount = 0.6 //购买用户用户名 val userName = "haiTao Jiang" //用户手机号 val tel = "13372090488" //用户邮箱 val email = "34650965@qq.com" //订单号 val orderId = "111122223333" //订单金额 val orderAmount = 119.4 }
} |
2.3 标识符的命名规范
Scala 对各种变量、方法、函数等命名时使用的字符序列称为标识符。即:凡是自己可 以起名字的地方都叫标识符。 |
命名规则:
Scala 中的标识符声明,基本和 Java 是一致的,但是细节上会有所变化,总结后有三点:
- 以字母或者下划线开头,后接字母、数字、下划线 正常情况下:字母加下划线偶尔来个数字
- 以操作符开头,且只包含操作符(+ - / # !等)
- 用反引号`....`包括的任意字符串,即使是 Scala 关键字(39 个)也可以
• package, import, class, object, trait, extends, with, type, for • private, protected, abstract, sealed, final, implicit, lazy, override • try, catch, finally, throw • if, else, match, case, do, while, for, return, yield • def, val, var • this, super • new • true, false, null |
练一练:
需求:判断 hello、Hello12、1hello、h-b、x h、h_4、_ab、Int、_、+*-/#!、+*-/#!1、if、`if`,这些名字是否合法。
Scala object Test01 { def main(args: Array[String]): Unit = { // (1)以字母或者下划线开头,后接字母、数字、下划线 var hello: String = "" // ok var Hello12: String = "" // ok var 1hello: String = "" // error 数字不能开头 var h-b: String = "" // error 不能用- var x h: String = "" // error 不能有空格 var h_4: String = "" // ok var _ab: String = "" // ok var Int: String = "" // ok 因为在 Scala 中 Int 是预定义的字符,不是关键字,但不推荐 var _: String = "hello" // ok 单独一个下划线不可以作为标识符,因为_被认为是一个方法println(_) //(2)以操作符开头,且只包含操作符(+ - * / # !等) var +*-/#! : String = "" // ok var +*-/#!1 : String = "" // error 以操作符开头,必须都是操作符 //(3)用反引号`....`包括的任意字符串,即使是 Scala 关键字(39 个)也可以 var if : String = "" // error 不能用关键字 var `if` : String = "" // ok 用反引号`....`包括的任意字符串,包括关键字 } } |
2.4 字符串输出
基本语法:
- 字符串,通过+号连接
- printf 用法:字符串,通过%传值。
- 字符串模板(插值字符串):通过$获取变量值
代码测试:
Scala package com.doitedu.demo04 object TestString{ def main(args: Array[String]): Unit = { var name: String = "jinlian" var age: Int = 18 //(1)字符串,通过+号连接 println(name + " " + age) //可以用$来引用变量,大括号{}可以写也可以不写,如果不写,中间要用空格隔开 //最前面小写的s就是固定写法,写了他相当于就是一个模板字符串,咱们可以用$去引用变量了 println(s"${name}今年${age}岁了") //(2)printf 用法字符串,通过%传值。 他是不换行的,如果需要换行,那么要用\r\n来写在末尾换行 printf("name=%s age=%d\r\n",name,age) val price = 119.99 printf("这个商品的价格是%.2f",price)
//(3)字符串,通过$引用 //多行字符串,在 Scala中,利用三个双引号包围多行字符串就可以实现。 //输入的内容,带有空格、\t 之类,导致每一行的开始位置不能整洁对齐。 //应用 scala 的 stripMargin 方法,在 scala 中 stripMargin 默认 是“|”作为连接符,//在多行换行的行头前面加一个“|”符号即可。 val sql = """ |select |name, |count(1) as cnt |from |table_a |where name = "zhangSan" |and age = 18 |group by name; |""".stripMargin println(sql ) //如果需要对变量进行运算,那么可以加${} val sql01 = """ |select |name, |count(1) as cnt |from |table_a |where name = "$name" |and age = ${age+2} |group by name; |""".stripMargin println(sql01 ) val s2 = s"name=$name" println(s2) } } |
printf中格式化输出的模板 %d 十进制数字 %s 字符串 %c 字符 %e 指数浮点数 %f 浮点数 %i 整数(十进制) %o 八进制 %u 无符号十进制 %x 十六进制 |
2.5 数据类型(重点)
Java基本类型:char、byte、short、int、long、float、double、boolean
Java引用类型:(对象类型)
Java基本类型的包装类:Character、Byte、Short、Integer、Long、Float、Double、Boolean
由于Java有基本类型,而且基本类型不是真正意义的对象,即使后面产生了基本类型的包装类,但是仍然存在基本数据类型,所以Java语言并不是真正意思的面向对象。
- scala中的数据类型和java中数据类型最大的区别就是scala中的数据类型都是对象 , 也就是scala中没有原生的数据类型!
- scala中的数据类型分成两类 AnyVal(值类型)和AnyRef(引用类型) , 两种对象都属于Any ,都是对象
val age:Int = 23
age是一个Int数值类型的变量 , 数值类型的变量也属于一个对象 , 所以age变量就是一个对象,也拥有很多方法
注意:Java中基本类型和引用类型没有共同的祖先。

- Any : 所有类型的父类 , 类似于java中的Object
- AnyVal: 数值类型(简单类型) ==-》 对应的是java中的基本数据类型
- AnyRef: 引用数据类型
- Null: 引用类型的子类,类似于java中的null ==》 写了一个类,将null这个值封装在了这个Null里面
- Unit:对应Java中的void,表示方法没有返回值 ,他的值:() ==》 因为针对这个对象,重写了toString 方法
- Nothing: 所类型的子类,主要用在一个函数没有明确返回值时使用,通常异常时使用,表示此处有错

数据类型详细表:

点击图片可查看完整电子表格
Unit 类型、Null 类型和 Nothing 类型
数据类型 | 描述 |
Unit | 表示无值,和其他语言中 void 等同。用作不返回任何结果的方法的结果类型。Unit 只有一个实例值,写成()。 |
Null | null , Null 类型只有一个实例值 null |
Nothing | Nothing 类型在 Scala 的类层级最低端;它是任何其他类型的子类型。当一个函数,我们确定没有正常的返回值,可以用 Nothing 来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数或者变量(兼容性) |
2.6 类型转换
当Scala 程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数值类型,这
个就是自动类型转换(隐式转换)。数据类型按精度(容量)大小排序为:

说明:
- 自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数据类型,然后再进行计算。
- 把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。toInt toDouble
- (byte,short)和 char 之间不会相互自动转换。
- byte,short,char 他们三者可以计算,在计算时首先转换为 int 类型。
测试案例:
Scala object Test { def main(args: Array[String]): Unit = { //(1)自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数值类型,然后再进行计算。 var n = 1 + 2.0 println(n) // n 就是 Double //(2)把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。 var n2 : Double= 1.0 //var n3 : Int = n2 //错误,原因不能把高精度的数据直接赋值和低精度。 //(3)(byte,short)和 char 之间不会相互自动转换。 var n4 : Byte = 1 //var c1 : Char = n4 //错误 var n5:Int = n4 //(4)byte,short,char 他们三者可以计算,在计算时首先转换为 int类型。 var n6 : Byte = 1 var c2 : Char = 1 // var n : Short = n6 + c2 //当 n6 + c2 结果类型就是 int // var n7 : Short = 10 + 90 //错误 } } |
第 3 章 运算符 基本和java一样
3.1算术运算符

测试代码:
Scala object Test { def main(args: Array[String]) { var a = 10; var b = 20; var c = 25; var d = 25; println("a + b = " + (a + b) ); println("a - b = " + (a - b) ); println("a * b = " + (a * b) ); println("b / a = " + (b / a) ); println("b % a = " + (b % a) ); println("c % a = " + (c % a) ); } } |
3.2关系运算符

点击图片可查看完整电子表格
代码测试:
Scala def main(args: Array[String]) { var a = 10; var b = 20; println("a == b = " + (a == b) ); println("a != b = " + (a != b) ); println("a > b = " + (a > b) ); println("a < b = " + (a < b) ); println("b >= a = " + (b >= a) ); println("b <= a = " + (b <= a) ); } |
3.3逻辑运算符

点击图片可查看完整电子表格
代码测试:
Scala val a = true val b = false
println("a && b = " + (a && b))//false
println("a || b = " + (a || b))//true
println("!(a && b) = " + !(a && b))//true |
3.4赋值运算符
注意:scala中是没有++ -- 替换 += -=

点击图片可查看完整电子表格
代码测试:
Scala object Test { def main(args: Array[String]): Unit = { var r1 = 10 r1 += 1 // 没有++ r1 -= 2 // 没有-- } } |
3.5 位运算符

测试代码:
Scala object TestPosition { def main(args: Array[String]): Unit = { // 测试:1000 << 1 =>10000 var n1 :Int =8 n1 = n1 << 1 println(n1) //16 } } |
3.6优先级

第 4 章 流程控制 (和java一样)
4.1 分支控制 if-else
让程序有选择的的执行,分支控制有三种:单分支、双分支、多分支
4.1.1 单分支
基本语法
Scala //说明:当条件表达式为 ture 时,就会执行{ }的代码。 if (条件表达式) { 执行代码块 } |
需求:现在hadoop的课程是199元,如果说今天是程序员节(10月24号),那么今天购买商品打6折,并将订单金额打印在控制台上
Scala package com.doitedu
object Demo02 { /** * 需求:现在hadoop的课程是199元,如果说今天是程序员节(10月24号),那么今天购买商品打6折,并将订单金额打印在控制台上 */ def main(args: Array[String]): Unit = { //课程名称:java基础,mysql,hadoop..... var subjectName = "hadoop" //课程的价格:199,299,399,99 val subjectPrice = 199.00 val activeType = "程序员节" //活动折扣力度 val activeDiscount = 0.6 //订单金额 var orderAmount = 0.0 if(activeType == "程序员节"){ orderAmount = subjectPrice * activeDiscount println(orderAmount) } } } |
4.1.2 双分支
基本语法
Scala if (条件表达式) { 执行代码块 1 } else { 执行代码块 2 } |
需求:现在hadoop的课程是199元,如果说今天是程序员节(10月24号),那么今天购买商品打6折,如果不是,就需要按照原价购买,最后将订单金额打印在控制台上
Scala package com.doitedu
object Demo02 { /** * 需求:现在hadoop的课程是199元,如果说今天是程序员节(10月24号),那么就给这个价格打6折 */
def main(args: Array[String]): Unit = { //课程名称:java基础,mysql,hadoop..... var subjectName = "hadoop" //课程的价格:199,299,399,99 val subjectPrice = 199.00 val activeType = "程序员节" //活动折扣力度 val activeDiscount = 0.6 //订单金额 var orderAmount = 0.0 if(activeType =="程序员节"){ orderAmount = subjectPrice * activeDiscount println(orderAmount) }else{ orderAmount = subjectPrice println(orderAmount) }
if(activeType =="不是程序员节"){ orderAmount = subjectPrice * activeDiscount }else{ orderAmount = subjectPrice } println(orderAmount) } } |
4.1.3 多分支
基本语法
Scala if (条件表达式 1) { 执行代码块 1 } else if (条件表达式 2) { 执行代码块 2 } …… else { 执行代码块 n } |
需求:猜数字小游戏
Scala package com.doitedu
object Demo02 { def main(args: Array[String]): Unit = { //猜数字小游戏 /** * 1.生成一个目标数字 * 2.我输入一个数字开始猜,如果猜的数字比原来的数字大,就打印猜大了 * 如果猜的数字比原来的数字小,就打印猜小了 * 如果猜的数字和原来的数字相等,就打印,猜对了 */
val random: Random = new Random() val res: Int = random.nextInt(100) + 1
println( """ |在一个月黑风高的夜晚, |多易教育发行了一个比较low的猜数字游戏。 |听说猜对了连奖励都没有,哎,还是开始吧!!! |""".stripMargin) Thread.sleep(1000) println("3") Thread.sleep(1000) println("2") Thread.sleep(1000) println("1") Thread.sleep(1000) println("开始!!!")
val sc: Scanner = new Scanner(System.in)
var i = 5
while (i > 0 && i <= 5) {
println(s"请输入你要猜的数字!你还有${i}次机会!!") i -= 1 val num: Int = sc.nextInt() if (res > num) { if(i > 0 && i <= 5){ println("你不行啊,猜小了,下次猜大一点") }else{ println(s"没机会了,你挂了:${i}") } } else if (res < num) { if(i > 0 && i <= 5){ println("你不行啊,猜大了,下次猜小一点") }else{ println(s"没机会了,你挂了,正确的结果是:${i}") } } else { println("恭喜你,猜对了,但是没得奖励") return } } } } |
4.2 嵌套分支
在一个分支结构中又完整的嵌套了另一个完整的分支结构,里面的分支的结构称为内层。分支外面的分支结构称为外层分支。嵌套分支不要超过 3 层。
基本语法:
Scala if(条件表达式1){ if(条件表达式2){ 执行代码块 1 }else{ 执行代码块 2 } } |
需求:如果该用户参加的活动类型双十一光棍节,并且他是单身的话,就给他打5折,不是单身就给他打8折,最后订单金额打印在控制台上
Scala package com.doitedu
object Demo02 { /** * 需求:如果该用户参加的活动类型双十一光棍节,并且他是单身的话,就给他打5折,不是单身就给他打8折,最后订单金额打印在控制台上 */
def main(args: Array[String]): Unit = { //课程的价格:199,299,399,99 val subjectPrice = 199.00 val isMarry = "yes" //活动类型 val activeType = "光棍节" //订单金额 var orderAmount = 0.0
if (activeType == "光棍节") { if (isMarry == "yes") { orderAmount = subjectPrice * 0.8 }else{ orderAmount = subjectPrice * 0.5 } } println(orderAmount) } } |
4.3 Switch 分支结构
在 Scala 中没有 Switch,而是使用模式匹配来处理。
模式匹配涉及到的知识点较为综合,因此我们放在后面讲解。
4.4 For 循环控制
Scala 也为 for 循环这一常见的控制结构提供了非常多的特性,这些 for 循环的特性被称为 for 推导式或 for 表达式。
4.4.1 范围数据循环(To)
基本语法
Scala for(i <- 1 to 10){ println(i) } |
(1)i 表示循环的变量,<- 规定 to (2)i 将会从 1-3 循环,前后闭合 |
练习:
需求:输出 5 句 "hello world"
Scala object TestFor { def main(args: Array[String]): Unit = { for(i <- 1 to 5){ println("hello world"+i) } } } |
4.4.2 范围数据循环(Until)
基本语法:
Scala for(i <- 1 until 5) { println(i) } |
(1)这种方式和前面的区别在于 i 是从 1 到 5-1 即[0,5) (2)即使前闭合后开的范围 |
练习:
需求:用until输出 5 句 "hello world"
Scala object TestFor { def main(args: Array[String]): Unit = { for(i <- 1 until 5+1){ println("hello world"+i) } } } |
4.4.3 循环守卫
基本语法
Scala for(i <- 1 to 3 if i != 2) { println(i) } |
循环守卫,即循环保护式(也称条件判断式,守卫)。保护式为 true 则进入循环体内部,为 false 则跳过,类似于 continue。 |
代码等价:
Scala for (i <- 1 to 3){ if (i != 2) { print(i + " ") } } |
案例:
需求:输出 1 到 5 中,不等于 3 的值
Scala object TestFor { def main(args: Array[String]): Unit = { for (i <- 1 to 5 if i != 3) { println(i + "doit") } } } |
4.4.4 循环步长
基本语法:
说明:by 表示步长
Scala for (i <- 1 to 10 by 2) { println("i=" + i) } |
案例:
需求:输出 1 到 10 以内的所有奇数
Scala for (i <- 1 to 10 by 2) { println("i=" + i) }
结果: i=1 i=3 i=5 i=7 i=9 |
4.4.5 嵌套循环
基本语法:
说明:没有关键字,所以范围后一定要加;来隔断逻辑
Scala for(i <- 1 to 3; j <- 1 to 3) { println(" i =" + i + " j = " + j) } |
等价得代码:
Scala for (i <- 1 to 3) { for (j <- 1 to 3) { println("i =" + i + " j=" + j) } } |
需求:
打印九九乘法表
Scala object TestWhile { def main(args: Array[String]): Unit = { //需求,打印一个九九乘法表 for (i <- 1 to 9){ for (j <- 1 to i){ print(s"$i * $j = ${i*j} \t" ) } println() } } }
for(i <- 1 to 9;j <- 1 to i){ print(s"$i * $j = ${i*j} \t" ) if(i == j) println() }
|
输出结果:

4.4.6 引入变量:
基本语法:
Scala for(i <- 1 to 3; j = 4 - i) { println("i=" + i + " j=" + j) } |
说明:
(1)for 推导式一行中有多个表达式时,所以要加 ; 来隔断逻辑
(2)for 推导式有一个不成文的约定:当 for 推导式仅包含单一表达式时使用圆括号,当包含多个表达式时,一般每行一个表达式,并用花括号代替圆括号,如下
举例:
Scala for { i <- 1 to 3 j = 4 - i } { println("i=" + i + " j=" + j) } |
等价得代码:
Scala for (i <- 1 to 3) { var j = 4 - i println("i=" + i + " j=" + j) } |
4.4.7 循环返回值
基本语法:
Scala val res = for(i <- 1 to 10) yield i println(res) |
说明:将遍历过程中处理的结果返回到一个新 Vector 集合中,使用 yield 关键字。
练习:需求:将原数据中所有值乘以 2,并把数据返回到一个新的集合中。
Scala object TestFor { def main(args: Array[String]): Unit = { var res = for(i <-1 to 10) yield { i * 2 } println(res) } }
输出结果: Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20) |
4.4.8 倒序打印
说明:如果想倒序打印一组数据,可以用 reverse。
案例:需求:倒序打印 10 到 1
Scala for(i <- 1 to 10 reverse){ println(i) } |
练一练:
需求:倒序打印100-1000里面所有的水仙花数
水仙花数:指一个 3 位数,它的每个位上的数字的 3次幂之和等于它本身
Scala def main(args: Array[String]): Unit = { for (elem:Int <- 100 until 1000 reverse ;if pow(elem % 10,3)+pow(elem / 10 % 10,3)+pow(elem / 100 % 10,3) == elem ) { println("水仙花数是: "+elem) } } |