• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Scala基础学习

武飞扬头像
Maverick_曲流觞
帮助1

1. 输出语句和分号

1.1 输出语句

方式一: 换行输出

格式:  println(里边写你要打印到控制台的数据);

方式二: 不换行输出

格式: print(里边写你要打印到控制台的数据);

注意: 不管是println(), 还是print()语句, 都可以同时打印多个值.格式为: println(值1, 值2, 值3...)

1.2 分号

Scala语句中, 单行代码最后的分号可写可不写. 如果是多行代码写在一行, 则中间的分号不能省略, 最后一条代码的分号可省略不写.

示例:

println("Hello, Scala!")			//最后的分号可写可不写
//如果多行代码写在一行, 则前边语句的分号必须写, 最后一条语句的分号可以省略不写.
println("Hello"); println("Scala")	

2. Scala中的常量

2.1 概述

常量指的是: 在程序的运行过程中, 其值不能发生改变的量.

2.2 分类

  • 字面值常量(常用的有以下几种)
    • 整型常量
    • 浮点型常量
    • 字符常量
    • 字符串常量
    • 布尔常量
    • 空常量
  • 自定义常量(稍后解释)

2.3 代码演示

//整型常量
println(10)
//浮点型常量
println(10.3)
//字符常量, 值要用单引号括起来
println('a')
//字符串常量, 值要用双引号括起来
println("abc")
//布尔常量, 值只有true和false
println(true)
//空常量
println(null)

3. Scala中的变量

3.1 概述

变量, 指的就是在程序的执行过程中, 其值可以发生改变的量. 定义格式如下:

3.2 语法格式

Java变量定义

int a = 0;

在scala中,可以使用val或者var来定义变量,语法格式如下:

val/var 变量名:变量类型 = 初始值

其中

  • val定义的是不可重新赋值的变量, 也就是自定义常量,类似Java中的final.
  • var定义的是可重新赋值的变量

注意: scala中定义变量时, 类型写在变量名后面

注意: 优先使用val定义变量,如果变量需要被重新赋值,才使用var

3.3 使用类型推断来定义变量

scala的语法要比Java简洁,可以使用一种更简洁的方式来定义变量。

示例

使用更简洁的语法定义一个变量保存一个人的名字"tom"

参考代码

scala> val name = "tom"
name: String = tom

scala可以自动根据变量的值来自动推断变量的类型,这样编写代码更加简洁。

4. 字符串

scala提供多种定义字符串的方式,将来我们可以根据需要来选择最方便的定义方式。

  • 使用双引号
  • 使用插值表达式
  • 使用三引号

4.1 使用双引号

语法

val/var 变量名 = “字符串”

示例

有一个人的名字叫"hadoop",请打印他的名字以及名字的长度。

参考代码

println(name   name.length)  //hadoop6

4.2 使用插值表达式

scala中,可以使用插值表达式来定义字符串,有效避免大量字符串的拼接。

语法

val/var 变量名 = s"${变量/表达式}字符串"

注意:

  • 在定义字符串之前添加s
  • 在字符串中,可以使用${}来引用变量或者编写表达式

示例

请定义若干个变量,分别保存:“zhangsan”、23、“male”,定义一个字符串,保存这些信息。

打印输出:name=zhangsan, age=23, sex=male

参考代码

 val name = "zhangsan"
 val age = 23
 val sex = "male"
 val result = s"name=${name}, age=${age}, sex=${sex}"
 println(result)   // name=zhangsan, age=23, sex=male

4.3 使用三引号

如果有大段的文本需要保存,就可以使用三引号来定义字符串。例如:保存一大段的SQL语句。三个引号中间的所有内容都将作为字符串的值。

语法

val/var 变量名 = """字符串1
字符串2"""

示例

定义一个字符串,保存以下SQL语句

select
	*
from
    t_user
where
    name = "zhangsan"

打印该SQL语句

参考代码

    val sql ="""select
        | *
        | from
        |     t_user
        | where
        |     name = "zhangsan"""".stripMargin

    println(sql)

4.4 扩展: 惰性赋值

当有一些变量保存的数据较大时,而这些数据又不需要马上加载到JVM内存中。就可以使用惰性赋值来提高效率。
语法格式:

lazy val/var 变量名 = 表达式

示例
在程序中需要执行一条以下复杂的SQL语句,希望只有用到这个SQL语句才加载它。
参考代码

    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. 数据类型

5.1 简述

数据类型是用来约束变量(常量)的取值范围的. Scala也是一门强类型语言, 它里边的数据类型绝大多数和Java一样.

  • 与Java不一样的一些用法
  • scala中数据类型的继承体系

5.2 数据类型

基础类型 类型说明
Byte 8位带符号整数
Short 16位带符号整数
Int 32位带符号整数
Long 64位带符号整数
Char 16位无符号Unicode字符
String Char类型的序列(字符串)
Float 32位单精度浮点数
Double 64位双精度浮点数
Boolean true或false

注意下 scala类型与Java的区别

  1. scala中所有的类型都使用大写字母开头
  2. 整形使用Int而不是Integer
  3. scala中定义变量可以不写类型,让scala编译器自动推断
  4. Scala中默认的整型是Int, 默认的浮点型是: Double

5.3 Scala类型层次结构

学新通

类型 说明
Any 所有类型的父类,它有两个子类AnyRef与AnyVal
AnyVal 所有数值类型的父类
AnyRef **所有对象类型(引用类型)**的父类
Unit 表示空,Unit是AnyVal的子类,它只有一个的实例{% em %}() {% endem %} 它类似于Java中的void,但scala要比Java更加面向对象
Null Null是AnyRef的子类,也就是说它是所有引用类型的子类。可以将null赋值给任何对象类型
Nothing 所有类型的子类, 不能直接创建该类型实例,某个方法抛出异常时,返回的就是Nothing类型,因为Nothing是所有类的子类,那么它可以赋值为任何类型

6. 类型转换

6.1 概述

当Scala程序在进行运算或者赋值动作时, 范围小的数据类型值会自动转换为范围大的数据类型值, 然后再进行计算.例如: 1 1.1的运算结果就是一个Double类型的2.1. 而有些时候, 我们会涉及到一些类似于"四舍五入"的动作, 要把一个小数转换成整数再来计算. 这些内容就是Scala中的类型转换.

Scala中的类型转换分为值类型的类型转换引用类型的类型转换,
值类型的类型转换分为:

  • 自动类型转换
  • 强制类型转换

6.2 自动类型转换

  1. 解释

    范围小的数据类型值会自动转换为范围大的数据类型值, 这个动作就叫: 自动类型转换.

    自动类型转换从小到大分别为:Byte, Short, Char -> Int -> Long -> Float -> Double

  2. 示例代码

    val a:Int = 3
    val b:Double = 3   2.21	//因为是int类型和double类型的值进行计算, 所以最终结果为: Double类型
    val c:Byte = a   1	//这样写会报错, 因为最终计算结果是Int类型的数据, 将其赋值Byte类型肯定不行.
    

6.3 强制类型转换

  1. 解释

    范围大的数据类型值通过一定的格式(强制转换函数)可以将其转换成范围小的数据类型值, 这个动作就叫: 强制类型转换.

    注意: 使用强制类型转换的时候可能会造成精度缺失问题!

  2. 格式

val/var 变量名:数据类型 = 具体的值.toXxx		//Xxx表示你要转换到的数据类型
  1. 参考代码
val a:Double = 5.21
val b:Int = a.toInt

6.4 值类型和String类型之间的相互转换

1. 值类型的数据转换成String类型

格式一:

val/var 变量名:String = 值类型数据   ""

格式二:

val/var 变量名:String = 值类型数据.toString

示例

将Int, Double, Boolean类型的数据转换成其对应的字符串形式.

参考代码:

val a1:Int = 10
val b1:Double = 2.1
val c1:Boolean = true

//方式一: 通过和空字符串拼接的形式实现
val a2:String = a1   ""
val b2:String = b1   ""
val c2:String = c1   ""

//方式二: 通过toString函数实现
val a3:String = a1.toString
val b3:String = b1.toString
val c3:String = c1.toString

2. String类型的数据转换成其对应的值类型

格式:

val/var 变量名:值类型 = 字符串值.toXxx	//Xxx表示你要转换到的数据类型

注意:

  • String类型的数据转成Char类型的数据, 方式有点特殊, 并不是调用toChar, 而是toCharArray
  • 这点目前先了解即可, 后续我们详细解释

需求:

将字符串类型的整数, 浮点数, 布尔数据转成其对应的值类型数据.

参考代码:

val s1:String = "100"
val s2:String = "2.3"
val s3:String = "false"

//将字符串类型的数据转成其对应的: Int类型
val a:Int = s1.toInt
//将字符串类型的数据转成其对应的: Double类型
val b:Double = s2.toDouble
//将字符串类型的数据转成其对应的: Boolean类型
val c:Boolean = s3.toBoolean

7. 键盘录入

7.1 使用步骤

  1. 导包

    格式: import scala.io.StdIn

  2. 通过StdIn.readXxx()来接收用户键盘录入的数据

    接收字符串数据: StdIn.readLine()

    接收整数数据: StdIn.readInt()

7.2 示例

  • 提示用户录入字符串, 并接收打印.

    println("请录入一个字符串: ")
    val str = StdIn.readLine()
    println("您录入的字符串内容为: "   str)
    
  • 提示用户录入整数, 并接收打印.

    println("请录入一个整数: ")
    val num = StdIn.readInt()
    println("您录入的数字为: "   num)
    

8. 运算符的分类

  • 算术运算符

  • 赋值运算符

  • 关系运算符

  • 逻辑运算符

  • 位运算符

    注意: Scala中是没有三元运算符的, 被if-else给替代了.

1. 算术运算符

算术运算符指的就是用来进行算术操作的符号, 常用的有以下几种:

运算符 功能解释
加号, 功能有3点. 1) 表示正数 2) 普通的加法操作 3) 字符串的拼接
- 减号, 功能有2点. 1) 表示负数 2) 普通的减法操作
* 乘号, 用于获取两个数据的乘积
/ 除法, 用于获取两个数据的商
% 取余(也叫取模), 用于获取两个数据的余数

注意:

  1. Scala中是没有 , --这两个算术运算符的, 这点和Java中不同.

  2. 整数相除的结果, 还是整数. 如果想获取到小数, 则必须有浮点型数据参与.

    例如: 10 / 3 结果是3 10 / 3.0 结果是: 3.3333(无限循环)

  3. 关于 号拼接字符串: 任意类型的数据和字符串拼接, 结果都将是一个新的字符串.

  4. 关于%操作, 假设求a % b的值, 它的底层原理其实是: a - a/b * b

1.1 代码演示

需求: 演示算术运算符的常见操作.

参考代码:

//演示 号操作
println( 3)
println(10   3)
println("hello"   10)

//演示-号操作
println(-5)
println(10 - 5)

//演示*号操作
println(5 * 3)

//演示/号操作
println(10 / 3)
println(10 / 3.0)

//演示%(取余)操作
println(10 % 3)     //结果是1, 具体运算过程: 10 - 10/3 * 3   = 10 - 3 * 3   = 1
println(10 % -3)    //结果是1, 具体运算过程: 10 - 10/-3 * -3 = 10 - -3 * -3 = 10 - 9  =  1
println(-10 % 3)   //结果是-1, 具体运算过程: -10 - -10/3 * 3 = -10 - -3 * 3 = -10   9 = -1 
学新通

2. 赋值运算符

2.1 概述

赋值运算符指的就是用来进行赋值操作的符号. 例如: 把一个常量值, 或者一个变量值甚至是某一段代码的执行结果赋值给变量, 这些都要用到赋值运算符.

2.2 分类

  • 赋值运算符常用的有两类

    • 基本赋值运算符

      =就是基本的赋值运算符, 例如: var a:Int = 3, 就是把常量值3赋值给变量a

    • 扩展赋值运算符

      =, -=, *=, /=, %=

    注意:

    1. 赋值运算符的左边必须是: 变量, 不能是常量. 例如: 3 = 5, 这种写法就是错误的.

    2. 关于扩展赋值运算符, 其实就是把左边的数据和右边的数据进行指定的操作, 然后把结果赋值给左边.

      例如; a = 3 就是把变量a的值和常量3进行加法操作, 然后把结果赋值给变量a

2.3 代码演示

//将常量值1赋值给变量a
var a:Int = 1			//注意: 因为后续代码要修改变量a的值, 所以变量a要用var修饰
//对变量a进行加3操作, 然后把结果重新赋值给变量a
a  = 3			//a的最终结果为: a = 4
//对变量a进行减2操作, 然后把结果重新赋值给变量a
a -= 2			//a的最终结果为: a = 2
//对变量a进行乘3操作, 然后把结果重新赋值给变量a
a *= 3			//a的最终结果为: a = 6
//对变量a进行除2操作, 然后把结果重新赋值给变量a
a /= 2			//a的最终结果为: a = 3
//对变量a和2进行取余操作, 然后把结果重新赋值给变量a
a %= 2			//a的最终结果为: a = 1

3. 关系运算符

3.1 概述

关系运算符指的就是用来进行比较操作的符号. 例如: 数据是否相等, 是否不等, 数据1大还是数据2大…等这些操作.

3.2 分类

运算符 功能解释
> 用来判断前边的数据是否大于后边的数据
>= 用来判断前边的数据是否大于或者等于后边的数据
< 用来判断前边的数据是否小于后边的数据
<= 用来判断前边的数据是否小于或者等于后边的数据
== 用来判断两个数据是否相等
!= 用来判断两个数据是否不等

注意:

  1. 关系表达式不管简单还是复杂, 最终结果一定是Boolean类型的值, 要么是true, 要么是false.
  2. 千万不要把==写成=, 否则结果可能不是你想要的.

3.3 代码演示

//定义两个Int类型的变量a, b, 分别赋值为3, 5
var a:Int = 3
var b:Int = 5
//判断a是否大于b, 并打印结果	
println(a > b)					//false
//判断a是否大于等于b, 并打印结果
println(a >= 3)					//true
//判断a是否小于b, 并打印结果
println(a < b)					//true
//判断a是否小于等于b, 并打印结果
println(a <= 3)					//true
//判断a和b是否不等, 并打印结果
println(a != b)					//true
//判断a和b是否相等, 并打印结果
println(a == b)					//false
//如果把==写成了=, 其实是把变量b的值赋值给变量a
println(a = b)					//输出结果是一对小括号"()", 即: 没有打印值.
println(a)						//再次打印变量a, 打印结果是:5
学新通

3.4 关系运算符延伸

需求描述 Scala代码 Java代码
比较数据值 == 或者 != equals()方法
比较引用值(地址值) eq方法 == 或者 !=

示例

有一个字符串"abc",再创建第二个字符串,值为:在第一个字符串后拼接一个空字符串。

然后使用比较这两个字符串是否相等、再查看它们的引用值是否相等。

参考代码

val s1 = "abc"
val s2 = s1   ""
s1 == s2     //结果是: true,  因为比较的是 数据值
s1.eq(s2)	 //结果是: false, 因为比较的是 地址值

4. 逻辑运算符

4.1 概述

逻辑运算符指的就是用来进行逻辑操作的符号. 可以简单理解为它是: 组合判断. 例如: 判断多个条件是否都满足, 或者满足其中的某一个, 甚至还可以对某个判断结果进行取反操作.

4.2 分类

运算符 功能解释
&& 逻辑与, 要求所有条件都满足(即: 结果为true), 简单记忆: 有false则整体为false.
|| 逻辑或, 要求只要满足任意一个条件即可, 简单记忆: 有true则整体为true.
! 逻辑非, 用来进行取反操作的. 即: 以前为true, 取反后为false, 以前为false, 取反后为true.

注意:

  1. 逻辑表达式不管简单还是复杂, 最终结果一定是Boolean类型的值, 要么是true, 要么是false.
  2. 在Scala代码中, 不能对一个Boolean类型的数据进行连续取反操作, 但是在Java中是可以的.
    • 即: !!false, 这样写会报错, 不支持这种写法.

4.3 代码演示

//相当于: false && true
println(3 > 5 && 2 < 3)		//结果为: false
//我们可以简写代码为:
//逻辑与: 有false则整体为false.
println(false && true)		//结果为: false
println(true && false)		//结果为: false
println(false && false)		//结果为: false
println(true && true)		//结果为: true

println(false || true)		//结果为: true
println(true || false)		//结果为: true
println(false || false)		//结果为: false
println(true || true)		//结果为: true

println(!false)				//结果为: true
println(!true)				//结果为: false
println(!!true)				//这样写会报错, Scala不支持这种写法, 但是Java代码支持这种写法.
学新通

5. 位运算符

5.1 进制

进制名称 数据组成规则 示例
二进制 数据以0b(大小写均可)开头, 由数字0和1组成 0b10001001, 0b00101010
八进制 数据以0开头, 由数字0~7组成 064, 011
十进制 数据直接写即可, 无特殊开头, 由数字0~9组成 10, 20, 333
十六进制 数据以0x(大小写均可)开头, 由数字0~9, 字母A-F组成(大小写均可) 0x123F, 0x66ABC

注意:

关于二进制的数据, 最前边的那一位叫: 符号位, 0表示正数, 1表示负数. 其他位叫: 数值位.

例如: 0b10001001 结果就是一个: 负数, 0b00101010 结果就是一个: 正数.

5.2 概述

位运算符指的就是按照位(Bit)来快速操作数据值, 它只针对于整型数据. 因为计算机底层存储, 操作, 运算采用的都是数据的二进制补码形式, 且以后要经常和海量的数据打交道, 为了提高计算效率, 就可以使用位运算符来实现快速修改数据值的操作.

5.3 分类

运算符 功能解释
& 按位与, 规则: 有0则0, 都为1则为1.
| 按位或, 规则: 有1则1, 都为0则为0.
^ 按位异或, 规则: 相同为0, 不同为1.
~ 按位取反, 规则: 0变1, 1变0.
<< 按位左移, 规则: 每左移一位, 相当于该数据乘2, 例如: 2 << 1, 结果为4
>> 按位右移, 规则: 每右移一位, 相当于该数据除2, 例如: 6 >> 1, 结果为3

注意:

  1. 位运算符只针对于整型数据.
  2. 运算符操作的是数据的二进制补码形式.
  3. 小技巧: 一个数字被同一个数字位异或两次, 该数字值不变. 即: 10 ^ 20 ^ 20, 结果还是10

5.4 代码演示

//定义两个变量a和b, 初始化值分别为: 3, 5
val a = 3			//二进制数据: 0000 0011
val b = 5			//二进制数据: 0000 0101

//结果为: 0000 0001, 转化成十进制, 结果为: 1
println(a & b)		//打印结果为: 1

//结果为: 0000 0111, 转化成十进制, 结果为: 7
println(a | b)		//打印结果为: 7

//结果为: 0000 0110, 转换成十进制, 结果为: 6
println(a ^ b)		//打印结果为: 6

//计算流程: 1111 1100(补码) -> 1111 1011(反码) -> 1000 0100(原码) -> 十进制数据: -4
println(~ a)		//打印结果为: -4

//计算流程: 1000 0011(-3原码) -> 1111 1100(-3反码) -> 1111 1101(-3补码) -> 0000 0010(取反后新补码) -> 十进制数据: 2
println(~ -3)		//打印结果为: 2

//计算流程: 0000 0011(3的补码) -> 0000 1100(新的补码) -> 十进制数据: 12
println(a << 2)		//打印结果为: 12

//计算流程: 0000 0011(3的补码) -> 0000 0001(新的补码) -> 十进制数据: 1
println(a >> 1)		//打印结果为: 1

println(a ^ b ^ b)	//打印结果为: 3
学新通

9.流程控制结构

1.分类

  • 顺序结构

  • 选择(分支)结构

  • 循环结构

    注意: Scala和Java中的流程控制结构是基本一致的.

2. 顺序结构

2.1 概述

顺序结构是指: 程序是按照从上至下, 从左至右的顺序, 依次逐行执行的, 中间没有任何判断和跳转.
如图:

学新通

注意: 顺序结构是Scala代码的默认流程控制结构.

2.2 代码演示

val a = 10
println("a: "   a)	//打印结果为10
println("Maverick ")
println("曲流觞 ")

3. 选择结构(if语句)

3.1 概述

选择结构是指: 某些代码的执行需要依赖于特定的判断条件, 如果判断条件成立, 则代码执行, 否则, 代码不执行.

3.2 分类

  • 单分支
  • 双分支
  • 多分支

3.3 单分支

所谓的单分支是指: 只有一个判断条件的if语句.

3.3.1 格式
if(关系表达式) {
    //具体的代码
}

注意: 关系表达式不管简单还是复杂, 结果必须是Boolean类型的值.

3.3.2 执行流程
  1. 先执行关系表达式, 看其结果是true还是false.
  2. 如果是true, 则执行具体的代码, 否则, 不执行.
  3. 如图:
    学新通
3.3.3 示例

**需求: **

定义一个变量记录某个学生的成绩, 如果成绩大于或者等于60分, 则打印: 分数及格.

参考代码

//定义变量, 记录成绩
val score = 61
//判断成绩是否不小于60分
if(score >= 60) {
    println("成绩及格")
}

3.4 双分支

所谓的双分支是指: 只有两个判断条件的if语句.

3.4.1 格式
if(关系表达式) {
    //代码1
} else {
    //代码2
}
3.4.2 执行流程
  1. 先执行关系表达式, 看其结果是true还是false.
  2. 如果是true, 则执行代码1. 如果是false, 则执行代码2.
  3. 如图:
    学新通
3.4.3 示例

**需求: **

定义一个变量记录某个学生的成绩, 如果成绩大于或者等于60分, 则打印: 分数及格, 否则打印分数不及格.

参考代码

//定义变量, 记录成绩
val score = 61
//判断成绩是否不小于60分
if(score >= 60) {
    println("成绩及格")
} else {
    println("成绩不及格")
}

3.5 多分支

所谓的多分支是指: 有多个判断条件的if语句.

3.5.1 格式
if(关系表达式1) {
    //代码1
} else if(关系表达式2) {
    //代码2
}else if(关系表达式n) {	//else if可以有多组
    //代码n
} else {
    //代码n 1			  //所有的关系表达式都不成立的时候, 执行这里的代码.
}
3.5.2 执行流程
  1. 先执行关系表达式1, 看其结果是true还是false.
  2. 如果是true, 则执行代码1, 分支语句结束. 如果是false, 则执行关系表达式2, 看其结果是true还是false.
  3. 如果是true, 则执行代码2. 分支语句结束. 如果是false, 则执行关系表达式3, 看其结果是true还是false.
  4. 以此类推, 直到所有的关系表达式都不满足, 执行最后一个else中的代码.
  5. 如图:
    学新通
3.5.3 示例

需求:

定义一个变量记录某个学生的成绩, 根据成绩发放对应的奖励, 奖励机制如下:

[90, 100] -> VR设备一套

[80, 90) -> 考试卷一套

[0, 80) -> 组合拳一套

其他 -> 成绩无效

参考代码

//定义变量, 记录成绩
val score = 80
//根据成绩发放对应的奖励
if(score >= 90 && score <= 100) {
    println("VR设备一套")
} else if(score >= 80 && score < 90) {
    println("考试卷一套")
} else if(score >= 0 && score < 80) {
    println("组合拳一套")
} else {
    println("成绩无效")
}

3.6 注意事项

if语句在使用时, 要注意的事项有以下三点:

  1. 和Java一样, 在Scala中, 如果大括号{}内的逻辑代码只有一行, 则大括号可以省略.
  2. 在scala中,条件表达式也是有返回值的
  3. 在scala中,没有三元表达式,可以使用if表达式替代三元表达式
    示例
    定义一个变量sex,再定义一个result变量,如果sex等于"male",result等于1,否则result等于0
    参考代码
//定义变量, 表示性别
val sex = "male"
//定义变量, 记录if语句的返回值结果
val result = if(sex == "male") 1 else 0
//打印结果为 result: 1
println("result: "   result)

3.7 嵌套分支

有些时候, 我们会涉及到"组合判断", 即一个分支结构中又嵌套了另一个分支结构, 这种写法就叫嵌套分支. 里边的那个分支结构叫: 内层分支, 外边的那个分支结构叫: 外层分支.
示例
定义三个变量a,b,c, 初始化值分别为: 10, 20, 30, 通过if分支语句, 获取其中的最大值.
思路分析

  1. 定义三个变量a, b, c, 分别记录要进行操作的值.
  2. 定义变量max, 用来记录获取到的最大值.
  3. 先判断a是否大于或者等于b.
  4. 条件成立, 说明 a大(或者等于b), 接着比较a和c的值, 获取最大值, 并将结果赋值给变量max
  5. 条件不成立, 说明 b大, 接着比较b和c的值, 获取最大值, 并将结果赋值给变量max
  6. 此时, max记录的就是a, b, c这三个变量的最大值, 打印即可.
    参考代码
//1. 定义三个变量a, b, c, 分别记录要进行操作的值.
val a = 10
val b = 20
val c = 30
//2. 定义变量max, 用来记录获取到的最大值.
var max = 0
//3. 先判断a是否大于或者等于b.
if(a >= b) {
    //4. 走这里说明a大(或者等于b), 接着比较a和c的值
    max = if(a >= c) a else c
} else {
    //5.  走这里说明b大, 接着比较b和c的值
    max = if(b >= c) b else c
}
//6. 打印max的值
println("max: "   max)
学新通

注意: 嵌套一般不超过3层.

3.8 扩展: 块表达式

  • scala中,使用{}表示一个块表达式
  • 和if表达式一样,块表达式也是有值的
  • 值就是最后一个表达式的值
    问题
    请问以下代码,变量a的值是什么?
val a = {
   println("1   1")
   1   1
}
println("a: "   a)     //1   1
              //a: 2

4. 循环结构

4.1分类

  • for循环
  • while循环
  • do.while循环

注意: 这三种循环推荐使用for循环, 因为它的语法更简洁, 更优雅.

4.2 for循环

在Scala中, for的格式和用法和Java中有些差异, Scala中的for表达式功能更加强大.

4.2.1 格式
for(i <- 表达式/数组/集合) {
    //逻辑代码
}

注意: 执行流程和Java一致

4.2.2 简单循环

**需求: **

打印10次"Hello, Scala!"

**参考代码: **

//定义一个变量, 记录1到10的数字
val nums = 1 to 10	//to是Scala中的一个关键字
//通过for循环, 打印指定的内容
for(i <- nums) {
     println("Hello, Scala! "   i)
}

**上述代码可以简写成: **

for(i <- 1 to 10) println("Hello, Scala! "   i)
4.2.3 嵌套循环

**需求: **使用for表达式,打印以下字符, 每次只能输出一个"*"

*****
*****
*****

步骤

  1. 使用for表达式打印3行,5列星星
  2. 每打印5个星星,换行

参考代码

//写法一: 普通写法
for(i <- 1 to 3) {		//外循环控制行数
    for(j <- 1 to 5) {	//内循环控制列数
        print("*")		//每次打印一个*
    }
    println()			//打印完一行(5个*)之后, 记得换行
}

//写法二: 压缩版
for(i <- 1 to 3) {		
    //这是两行代码
    for(j <- 1 to 5) if(j == 5) println("*") else print("*")
}

//写法三: 合并版
for(i <- 1 to 3; j <- 1 to 5) if(j == 5) println("*") else print("*")
学新通
4.2.4 守卫

for表达式中,可以添加if判断语句,这个if判断就称之为守卫。我们可以使用守卫让for表达式更简洁。

语法

for(i <- 表达式/数组/集合 if 表达式) {
    //逻辑代码
}

示例

使用for表达式打印1-10之间能够整除3的数字

参考代码

// 添加守卫,打印能够整除3的数字
for(i <- 1 to 10 if i % 3 == 0) println(i)
4.2.5 for推导式

Scala中的for循环也是有返回值的, 在for循环体中,可以使用yield表达式构建出一个集合(可以简单理解为: 就是一组数据),我们把使用yield的for表达式称之为推导式.

示例

生成一个10、20、30…100的集合

参考代码

// for推导式:for表达式中以yield开始,该for表达式会构建出一个集合
val v = for(i <- 1 to 10) yield i * 10
println(v)

4.3 while循环

4.3.1 格式
初始化条件
while(判断条件) {
    //循环体
    //控制条件
}
4.3.2 执行流程
  1. 执行初始化条件.
  2. 执行判断条件, 看其结果是true还是false.
  3. 如果是false则循环结束.
  4. 如果是true则执行循环体.
  5. 执行控制条件.
  6. 返回第二步, 重复执行.
4.3.3 示例

**需求: **

打印1-10的数字

参考代码

//初始化条件
var i = 1
//判断条件
while(i <= 10) {
    //循环体
    println(i)
    //控制条件
    i = i   1
}

4.4 do.while循环

4.4.1 格式
初始化条件
do{
    //循环体
    //控制条件
}while(判断条件) 
4.4.2 执行流程
  1. 执行初始化条件.
  2. 执行循环体.
  3. 执行控制条件.
  4. 执行判断条件, 看其结果是true还是false.
  5. 如果是false则循环结束.
  6. 如果是true则返回第2步继续执行.

注意:

  1. do.while循环不管判断条件是否成立, 循环体都会执行一次.
  2. for循环, while循环都是如果判断条件不成立, 则循环体不执行.
4.4.3 示例

**需求: **

打印1-10的数字

参考代码

//初始化条件
var i = 1
do{
    //循环体
    println(i)
    //控制条件
    i = i   1
}while(i <= 10)	//判断条件

4.5 break和continue

  • 在scala中,类似Java和C 的break/continue关键字被移除了
  • 如果一定要使用break/continue,就需要使用scala.util.control包下的Breaks类的breablebreak方法。
4.6.1 实现break

用法

  1. 导包.

    import scala.util.control.Breaks._

  2. 使用breakable将for表达式包起来

  3. for表达式中需要退出循环的地方,添加break()方法调用

示例

使用for表达式打印1-10的数字,如果遇到数字5,则退出for表达式

参考代码

// 导入scala.util.control包下的Break
import scala.util.control.Breaks._

breakable{
    for(i <- 1 to 10) {
        if(i == 5) break() else println(i)
    }
}
4.6.2 实现continue

用法

continue的实现与break类似,但有一点不同:

注意:

  1. 实现break是用breakable{}将整个for表达式包起来.
  2. 而实现continue是用breakable{}将for表达式的循环体包含起来就可以了.

示例
用for表达式打印1~10之间, 所有不能整除3的数字.

// 导入scala.util.control包下的Break    
import scala.util.control.Breaks._
for(i <- 1 to 100 ) {
    breakable{
        if(i % 3 == 0) break()
        else println(i)
    }
}

10.方法与函数

1. 方法

1.1 概述

scala中的方法和Java方法类似, 但scala与Java定义方法的语法是不一样的。

1.2 语法格式

def 方法名(参数名:参数类型, 参数名:参数类型) : [return type] = {
    //方法体
}

注意:

  • 参数列表的参数类型不能省略
  • 返回值类型可以省略,由scala编译器自动推断
  • 返回值可以不写return,默认就是{}块表达式的值

1.3 示例

**需求: **

  1. 定义一个方法getMax,用来获取两个整型数字的最大值, 并返回结果(最大值).
  2. 调用该方法获取最大值, 并将结果打印到控制台上.

参考代码

  • 方式一: 标准写法
//1. 定义方法, 用来获取两个整数的最大值.
def getMax(a:Int, b:Int): Int = {
    return if(a > b) a else b
}
//2. 调用方法, 获取最大值.
val max = getMax(10, 20)
//3. 打印结果.
println("max: "   max)
  • 方式二: 优化版
//1. 定义方法, 用来获取两个整数的最大值.
def getMax(a:Int, b:Int) = if(a > b) a else b
//2. 调用方法, 获取最大值.
val max = getMax(22, 11)
//3. 打印结果.
println("max: "   max)

1.4 返回值类型推断

scala定义方法可以省略返回值的数据类型,由scala自动推断返回值类型。这样方法定义后更加简洁。

注意: 定义递归方法,不能省略返回值类型

示例

定义递归方法, 求5的阶乘.

步骤

  1. 定义方法factorial, 用来计算某个数字的阶乘

    规律: 1的阶乘等于1, 其他数字的阶乘为: n! = n * (n - 1)!

  2. 调用方法, 获取5的阶乘, 并将结果打印到控制台上.

参考代码

//1. 定义方法factorial, 用来计算某个数字的阶乘
def factorial(n:Int):Int = if(n == 1) 1 else n * factorial(n - 1)   //省略:Int   会报错
//2. 调用方法, 获取5的阶乘.
val result = factorial(5)   
//3. 将结果打印到控制台上.
println("result: "   result)    
1.5 惰性方法

当记录方法返回值的变量被声明为lazy时, 方法的执行将被推迟, 直到我们首次使用该值时, 方法才会执行, 像这样的方法, 就叫: 惰性方法.

注意:

  1. Java中并没有提供原生态的"惰性"技术, 但是可以通过特定的代码结构实现, 这种结构被称之为: 懒加载(也叫延迟加载)
  2. lazy不能修饰var类型的变量.

使用场景:

  1. 打开数据库连接

    由于表达式执行代价昂贵, 因此希望能推迟该操作, 直到确实需要表达式结果值时才执行它

  2. 提升某些特定模块的启动时间.

    为了缩短模块的启动时间, 可以将当前不需要的某些工作推迟执行

  3. 确保对象中的某些字段能优先初始化

    为了确保对象中的某些字段能优先初始化, 我们需要对其他字段进行惰性化处理
    需求
    定义一个方法用来获取两个整数和, 通过"惰性"技术调用该方法, 然后打印结果.
    参考代码

//1. 定义方法, 用来获取两个整数和
def getSum(a:Int, b:Int) = {
    println("getSum方法被执行了...")
    a   b
}
//2. 通过"惰性"方式调用该方法.
lazy val sum = getSum(1, 2)		//此时我们发现getSum方法并没有执行, 说明它的执行被推迟了.

//3. 打印结果, 并观察
println("sum: "   sum) 			//打印结果为sum: 3, 说明首次使用方法返回值时, 方法才会加载执行.

1.6 方法参数

scala中的方法参数,使用比较灵活。它支持以下几种类型的参数:

  • 默认参数
  • 带名参数
  • 变长参数
1.6.1 默认参数

在定义方法时可以给参数定义一个默认值。

示例

  1. 定义一个计算两个整数和的方法,这两个值分别默认为10和20
  2. 调用该方法,不传任何参数

参考代码

//1. 定义一个方法, 用来获取两个整数的和
// x,y的默认值分别为10和20
def getSum(x:Int = 10, y:Int = 20) = x   y
//2. 通过默认参数的形式, 调用方法
val sum = getSum()
//3. 打印结果
println("sum: "   sum)
1.6.2 带名参数

在调用方法时,可以指定参数的名称来进行调用。

示例

  1. 定义一个计算两个整数和的方法,这两个值分别默认为10和20
  2. 调用该方法,只设置第一个参数的值

参考代码

//1. 定义一个方法, 用来获取两个整数的和
def getSum(x:Int = 10, y:Int = 20) = x   y
//2. 通过默认参数的形式, 调用方法
val sum = getSum(x=1)
val sum2 = getSum(y=1)
//3. 打印结果
println("sum: "   sum)
println("sum2: "   sum2)
1.6.3 变长参数

如果方法的参数是不固定的,可以将该方法的参数定义成变长参数。

语法格式:

def 方法名(参数名:参数类型*):返回值类型 = {
    //方法体
}

注意:

  1. 在参数类型后面加一个*号,表示参数可以是0个或者多个
  2. 一个方法有且只能有一个变长参数, 并且变长参数要放到参数列表的最后边.

**示例一: **

  1. 定义一个计算若干个值相加的方法
  2. 调用方法,传入以下数据:1,2,3,4,5

参考代码

//1. 定义一个计算若干个值相加的方法
def getSum(a:Int*) = a.sum   //   .sum是集合的一个方法
//2. 调用方法,传入一些整数, 并获取它们的和
val sum = getSum(1,2,3,4,5)
//3. 打印结果
println("sum: "   sum)

1.7 方法调用方式

在scala中,有以下几种方法调用方式:

  • 后缀调用法
  • 中缀调用法
  • 花括号调用法
  • 无括号调用法

注意: 在编写spark、flink程序时,会经常使用到这些方法调用方式。

1.7.1 后缀调用法

这种方法与Java没有区别, 非常简单.

语法

对象名.方法名(参数)

示例

使用后缀法调用Math.abs, 用来求绝对值

参考代码

//后缀调用法
Math.abs(-1)	//结果为1
1.7.2 中缀调用法

语法

对象名 方法名 参数

例如:1 to 10

注意: 如果有多个参数,使用括号括起来

示例

使用中缀法调用Math.abs, 用来求绝对值

//中缀调用法
Math abs -1		//结果为1

扩展: 操作符即方法

1   1

在scala中, - * / %等这些操作符和Java一样,但在scala中,

  • 所有的操作符都是方法
  • 操作符是一个方法名字是符号的方法
1.7.3 花括号调用法

语法

Math.abs{ 
    // 表达式1
    // 表达式2
}

注意: 方法只有一个参数,才能使用花括号调用法

示例

使用花括号调用法Math.abs求绝对值

参考代码

//花括号调用法
Math.abs{
println("曲流觞")
-10
}	
//结果为: 
//曲流觞
//10
1.7.4 无括号调用法

如果方法没有参数,可以省略方法名后面的括号
示例

  • 定义一个无参数的方法,打印"Hello, Scala!"
  • 使用无括号调用法调用该方法
    参考代码
//1. 定义一个无参数的方法,打印"Hello, Scala!"
def sayHello() = println("Hello, Scala!")
//2. 调用方法
sayHello

注意:

  1. 在Scala中, 如果方法的返回值类型是Unit类型, 这样的方法称之为过程(procedure)
  2. 过程的等号(=)可以省略不写. 例如:
def sayHello() = println("Hello, Scala!")   
//可以改写为
def sayHello() { println("Hello, Scala!") }	 //注意: 这个花括号{}不能省略

2. 函数

scala支持函数式编程

2.1 定义函数

语法

val 函数变量名 = (参数名:参数类型, 参数名:参数类型....) => 函数体

注意:

  • 在Scala中, 函数是一个对象(变量)
  • 类似于方法,函数也有参数列表和返回值
  • 函数定义不需要使用def定义
  • 无需指定返回值类型

2.2 示例

**需求: **

  1. 定义一个计算两个整数和的函数
  2. 调用该函数

参考代码

//1. 定义一个用来计算两个整数和的函数, 并将其赋值给变量sum
val getSum = (x:Int, y:Int) => x   y
//2. 调用函数.
val result = getSum(1,2)
//3. 打印结果
println("result: "   result)

2.3 方法和函数的区别

在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

2.4 方法转换为函数

有时候需要将方法转换为函数. 例如: 作为变量传递,就需要将方法转换为函数
格式

val 变量名 = 方法名 _		//格式为: 方法名   空格   下划线

注意: 使用 _即可将方法转换为函数
示例

  1. 定义一个方法用来计算两个整数和
  2. 将该方法转换为一个函数,并赋值给变量

参考代码

//1. 定义一个方法用来计算两个整数和
def add(x:Int, y:Int)= x   y
//2. 将该方法转换为一个函数,并赋值给变量
val a = add _
//3. 调用函数, 用来获取两个整数的和.
val result = a(1, 2)
//4. 打印结果
println("result: "   result)

3. 案例: 打印nn乘法表

3.1 需求

定义方法实现, 根据用户录入的整数, 打印对应的乘法表。
例如: 用户录入5,则打印55乘法表,用户录入9,则打印99乘法表。

3.2 步骤

  1. 定义方法(或者函数), 接收一个整型参数.
  2. 通过for循环嵌套实现, 根据传入的整数, 打印对应的乘法表.
  3. 调用方法(函数), 输出结果.
3.3参考代码
  • 方式一: 通过方法实现
//1. 定义一个方法, 接收一个整型参数.
def printMT(n:Int) = {   //Multiplication Table(乘法表)
    //2. 通过for循环嵌套实现, 根据传入的整数, 打印对应的乘法表.
    for(i <- 1 to n; j <- 1 to i) {
    	print(s"${j} * ${i} = ${j * i}\t"); 
        if(j==i) println()
    }
}
//3. 调用方法
printMT(5)

//优化版
def printMT(n:Int) = for(i <- 1 to n; j <- 1 to i) print(s"${j} * ${i} = ${j * i}"   (if(j==i) "\r\n" else "\t"))
  • 方式二: 通过函数实现
//1. 定义一个函数, 接收一个整型参数.
val printMT = (n:Int) => {
    //2. 通过for循环嵌套实现, 根据传入的整数, 打印对应的乘法表.
    for(i <- 1 to n; j <- 1 to i) {
    	print(s"${j} * ${i} = ${j * i}\t"); 
        if(j==i) println()
    }
}
//3. 调用函数
printMT(9)

//优化版
val printMT = (n:Int) => for(i <- 1 to n; j <- 1 to i) print(s"${j} * ${i} = ${j * i}"   (if(j==i) "\r\n" else "\t"))

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgabcka
系列文章
更多 icon
同类精品
更多 icon
继续加载