通过本篇文章来记录学习的笔记,有遗忘的地方很快能够记起。
1.Scala中的常量(常量指的是: 在程序的运行过程中, 其值不能发生改变的量.)
-
整型常量
-
浮点型常量
-
字符常量
-
字符串常量
-
布尔常量
-
空常量
代码示例:
//整型常量
println(10)
//浮点型常量
println(10.3)
//字符常量, 值要用单引号括起来
println('a')
//字符串常量, 值要用双引号括起来
println("abc")
//布尔常量, 值只有true和false
println(true)
//空常量
println(null)
2.Scala中的变量(变量, 指的就是在程序的执行过程中, 其值可以发生改变的量. )
语法格式:
val/var 变量名:变量类型 = 初始值
-
val
定义的是不可重新赋值的变量, 也就是自定义常量. -
var
定义的是可重新赋值的变量
代码示例:
//根据格式来写
var a: Int = 10
val b: String = "hello"
//简写
var c = 10
val d = "hello"
3.字符串
字符串的定义方式:
-
使用双引号
-
使用插值表达式
-
使用三引号
使用双引号 :
格式:
val/var 变量名 = “字符串”
代码示例:
val str = "hello world"
var str1 = "hello world"
使用插值表达式:
使用场景:避免大量字符串的拼接
格式:
val/var 变量名 = s"${变量/表达式}字符串"
代码示例:
var a = 10
var b = 20
println(s"${a}")
println(s"${b}")
println(s"${a + b}")
println(s"a + b = ${a + b}")
使用三引号:
使用场景:如果有大段的文本需要保存,就可以使用三引号来定义字符串。例如:保存一大段的SQL语句。三个引号中间的所有内容都将作为字符串的值。
格式:
val/var 变量名 = """字符串1
字符串2"""
代码示例:
var sql = """select
| *
|from
| t_user
|where
| name = "zhangsan"""".stripMargin
println(sql)
4.惰性赋值
使用场景:
在企业的大数据开发中,有时候会编写非常复杂的SQL语句,这些SQL语句可能有几百行甚至上千行。这些SQL语句,如果直接加载到JVM中,会有很大的内存开销, 如何解决这个问题呢?
当有一些变量保存的数据较大时,而这些数据又不需要马上加载到JVM内存中。就可以使用惰性赋值来提高效率。
格式:
lazy val 变量名 = 表达式
代码示例:
lazy val sql =
"""insert overwrite table adm.itcast_adm_personas
select
a.user_id,
a.user_name,
a.user_sex,
a.user_birthday,
a.user_age,
a.constellation,
a.province,
a.city,
a.city_level,
a.hex_mail,
a.op_mail,
a.hex_phone,
a.fore_phone,
a.figure_model,
a.stature_model,
b.first_order_time,
b.last_order_time,
...
d.month1_hour025_cnt,
d.month1_hour627_cnt,
d.month1_hour829_cnt,
d.month1_hour10212_cnt,
d.month1_hour13214_cnt,
d.month1_hour15217_cnt,
d.month1_hour18219_cnt,
d.month1_hour20221_cnt,
d.month1_hour22223_cnt
from gdm.itcast_gdm_user_basic a
left join gdm.itcast_gdm_user_consume_order b on a.user_id=b.user_id
left join gdm.itcast_gdm_user_buy_category c on a.user_id=c.user_id
left join gdm.itcast_gdm_user_visit d on a.user_id=d.user_id;""".stripMargin
5.标识符
标识符就是用来给变量, 方法, 类等起名字的.
命名规则:
-
必须由
大小写英文字母, 数字, 下划线_, 美元符$
, 这四部分任意组合组成. -
数字不能开头.
-
不能和Scala中的关键字重名.
-
最好做到见名知意.
命名规范:
- 变量或方法: 从第二个单词开始, 每个单词的首字母都大写, 其他字母全部小写(小驼峰命名法).
- 类或特质(Trait): 每个单词的首字母都大写, 其他所有字母全部小写(大驼峰命名法)
- 包: 全部小写, 一般是公司的域名反写, 多级包之间用.隔开.
6.数据类型
scala类型层次结构:
7.类型转换
值类型的类型转换分为:
-
自动类型转换
-
强制类型转换
自动类型转换:
自动类型转换从小到大分别为:Byte, Short, Char -> Int -> Long -> Float -> Double
代码示例:
var a = 3
var b = 3.3
var c = a + b
println(a.getClass.getSimpleName)
println(b.getClass.getSimpleName)
println(c.getClass.getSimpleName) //c自动转换为double类型
强制类型转换:
范围大的数据类型值通过一定的格式(强制转换函数)可以将其转换成范围小的数据类型值, 这个动作就叫: 强制类型转换.
注意: 使用强制类型转换的时候可能会造成精度缺失问题!
格式:
val/var 变量名:数据类型 = 具体的值.toXxx //Xxx表示你要转换到的数据类型
代码示例:
var a = 10.5
var b = a.toInt
println(a)
println(b)
println(a.getClass.getSimpleName)
println(b.getClass.getSimpleName)
值类型和String类型之间的相互转换:
1.值类型的数据转换成String类型:
格式一:
val/var 变量名:String = 值类型数据 + ""
格式二:
val/var 变量名:String = 值类型数据.toString
代码示例:
var a = 10
var b = 2.3
var c = true
//方式一
var a1 = a + ""
var b1 = b + ""
var c1 = c + ""
println(a1.getClass.getSimpleName)
println(b1.getClass.getSimpleName)
println(c1.getClass.getSimpleName)
//方式二
var a2 = a.toString
var b2 = b.toString
var c2 = c.toString
println(a2.getClass.getSimpleName)
println(b2.getClass.getSimpleName)
println(c2.getClass.getSimpleName)
2.String类型的数据转换成其对应的值类型
格式:
val/var 变量名:值类型 = 字符串值.toXxx //Xxx表示你要转换到的数据类型
- String类型的数据转成Char类型的数据, 方式有点特殊, 并不是调用toChar, 而是toCharArray
代码示例:
var a = "100"
var b = "100.100"
var c = "false"
var d = "hello world"
var a1 = a.toInt
var b1 = b.toDouble
var c1 = c.toBoolean
var d1 = d.toCharArray
println(a1.getClass.getSimpleName)
println(b1.getClass.getSimpleName)
println(c1.getClass.getSimpleName)
println(d1.getClass.getSimpleName)
键盘录入
代码示例:
var str = StdIn.readLine("请输入一个字符串:")
println(str)
println("请输入一个整数:")
var num = StdIn.readInt()
println(num)
运算符
-
算术运算符:+ - * / % (Scala中没有++,--)
-
赋值运算符: = += -= .......
-
关系运算符: > < >= <= == !=
-
逻辑运算符:&& || !
-
位运算符
Scala流程控制
-
顺序结构 :程序是按照从上至下, 从左至右的顺序, 依次逐行执行的, 中间没有任何判断和跳转.
-
选择(分支)结构:if... if...else... if... else if... else
-
循环结构:for while do.while
重点说一下循环结构:
在Scala中, for的格式和用法和Java中有些差异, Scala中的for表达式功能更加强大.
格式:
for(i <- 表达式/数组/集合) {
//逻辑代码
}
代码示例:
打印10次"Hello, Scala!"
var nums = 1 to 10
for (i <- nums) {
println("Hello,Scala")
}
上述代码可以简写成:
for (i <- 1 to 10) println("Hello,Scala " + i)
守卫
for表达式中,可以添加if判断语句,这个if判断就称之为守卫,过滤出一些满足条件的结果。。我们可以使用守卫让for表达式更简洁。
格式:
for(i <- 表达式/数组/集合 if 表达式) {
//逻辑代码
}
代码示例:
使用for表达式打印1-10之间能够整除3的数字
for (i <- 1 to 10 if i % 3 == 0) println(i)
for推导式
for结构可以在每次执行的时候创造一个值,然后将包含了所有产生值的集合作为for循环表达式的结果返回,集合的类型由生成器中的集合类型确定。注意:for 循环中的 yield 会把当前的元素记下来,保存在集合中,循环结束后将返回该集合。Scala 中 for 循环是有返回值的。如果被循环的是 Map,返回的就是 Map,被循环的是 List,返回的就是 List,以此类推。
格式:
for (变量 <- 表达式) yield {语句块}
代码示例:
生成一个10、20、30...100的集合
var data = for (i <- 1 to 10) yield i * 10
println(data)
println(data.getClass.getSimpleName)
While循环
scala中while循环和Java中是一致的, 所以学起来非常简单.
语法:
初始化条件
while(判断条件) {
//循环体
//控制条件
}
代码示例:
var num = 0
while (num <= 10) {
println(num)
num = num + 1
}
break和continue
-
在scala中,类似Java和C++的break/continue关键字被移除了
-
如果一定要使用break/continue,就需要使用scala.util.control包下的Breaks类的breable和break方法。
使用breakable代码示例:
breakable {
for (i <- 1 to 10) {
if (i == 5) {
break()
}
println(i)
}
}
实现continue代码示例:
for (i <- 1 to 10) {
breakable {
if (i % 3 == 0) {
break()
}
println(i)
}
}
实现一个九九乘法表:
for (i <- 1 to 9) {
for (j <- 1 to i) {
print(s"${j} * ${i} = ${j * i}\t")
}
println()
}
Scala函数和方法
1.方法
格式:
def 方法名(参数名:参数类型, 参数名:参数类型) : [return type] = {
//方法体
}
-
参数列表的参数类型不能省略
-
返回值类型可以省略,由scala编译器自动推断
-
返回值可以不写return,默认就是{}块表达式的值
代码示例:
-
定义一个方法getMax,用来获取两个整型数字的最大值, 并返回结果(最大值).
-
调用该方法获取最大值, 并将结果打印到控制台上.
//方法一:标准写法
def getMax(a: Int, b: Int): Int = {
return if (a > b) a else b
}
val max = getMax(45, 20)
println(max)
//方法二:优化版
def getMax1(a: Int, b: Int) = if (a > b) a else b
val max1 = getMax1(12, 23)
println(max1)
scala定义方法可以省略返回值的数据类型,由scala自动推断返回值类型。这样方法定义后更加简洁。
代码示例:定义递归方法, 求5的阶乘.
//方法一:标准写法
def factor(n: Int): Int = {
if (n == 1) {
return 1
}
return n * factor(n - 1)
}
var num = factor(5)
println(num)
//方法二:优化版
def factor1(n: Int): Int = if (n == 1) 1 else n * factor1(n - 1)
var num1 = factor1(5)
println(num1)
函数
scala支持函数式编程,将来编写Spark/Flink程序会大量使用到函数, 目前, 我们先对函数做一个简单入门, 在后续的学习过程中, 我们会逐步重点讲解函数的用法.
语法:
val 函数变量名 = (参数名:参数类型, 参数名:参数类型....) => 函数体
-
在Scala中, 函数是一个对象(变量)
-
类似于方法,函数也有参数列表和返回值
-
函数定义不需要使用
def
定义 -
无需指定返回值类型
代码示例:
-
定义一个计算两个整数和的函数
-
调用该函数
val getSum = (a: Int, b: Int) => a + b
var result = getSum(1, 2)
println(result)
方法和函数的区别
在Java中, 方法和函数之间没有任何区别, 只是叫法不同. 但是在Scala中, 函数和方法就有区别了, 具体如下:
-
方法是隶属于类或者对象的,在运行时,它是加载到JVM的方法区中
-
可以将函数对象赋值给一个变量,在运行时,它是加载到JVM的堆内存中
-
函数是一个对象,继承自FunctionN,函数对象有apply,curried,toString,tupled这些方法。方法则没有
结论: 在Scala中, 函数是对象, 而方法是属于对象的, 所以可以理解为: 方法归属于函数.
代码示例:
//1. 定义方法
def add(x:Int,y:Int)= x + y
//2. 尝试将方法赋值给变量.
//val a = add(1, 2) //不要这样写, 这样写是在"调用方法", 而不是把方法赋值给变量
val a = add
//3. 上述代码会报错
<console>:12: error: missing argument list for method add
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `add _` or `add(_,_)` instead of `add`.
val a = add
方法转换为函数
有时候需要将方法转换为函数. 例如: 作为变量传递,就需要将方法转换为函数
格式:
val 变量名 = 方法名 _ //格式为: 方法名 + 空格 + 下划线
代码示例:
-
定义一个方法用来计算两个整数和
-
将该方法转换为一个函数,并赋值给变量
def add(a: Int, b: Int): Int = {
return a + b
}
var sum = add _
var result = sum(1, 2)
println(result)