大数据处理学习笔记1.5 掌握Scala内建控制结构

文章目录

零、本讲学习目标

一、条件表达式

(一)语法格式

(二)执行情况

(三)案例演示

任务1、根据输入值的不同进行判断

任务2、编写Scala程序,判断奇偶性

二、块表达式

(一)语法格式

(二)执行情况

(三)案例演示

三、for循环

(一)单重for循环

1、语法格式

2、执行情况

3、案例演示

任务1:输出1到10

任务2、遍历字符串,输出每个字符

任务3、计算 1 + 2 + 3 + ... + 100

任务4、输出列表内的偶数(过滤)

任务5、输出全部两位素数

(二)嵌套for循环

1、语法格式

2、案例演示

任务1、打印九九表

方法一、采用双重循环来实现

方法二、采用单重循环来实现

方法三、采用单重循环与流间变量绑定来实现

方法四、采用单重循环、流间变量与yield来实现

任务2、去掉对角线

课堂练习:编程求解百钱买百鸡问题

四、条件循环

(一)while循环

1、语法格式

2、案例演示

任务1、计算1+ 2 + 3 + ... + 100

任务2、打印全部水仙花数

(二)do while循环

1、语法格式

2、案例演示

任务:计算1+ 2 + 3 + ... + 100

五、异常处理

(一)异常处理概述

(二)案例演示

任务:演示try-catch-finally

六、match结构

(一)语法格式

(二)案例演示

任务:给城市下评语

七、变量作用域

(一)Java变量作用域

1、内部能访问外部

2、外部不能看内部

(二)Scala变量作用域

1、内部不能访问外部

2、外部不能访问内部

八、补充案例

任务:评定成绩等级

1、编写符合函数式编程风格的Sala程序

2、函数式风格的程序有几个特点

3、非函数式风格的程序

零、本讲学习目标

  1. 掌握条件表达式

  1. 掌握各种循环

  1. 理解流间变量绑定

  1. 掌握yield语句的使用

  1. 掌握异常处理语句

  1. 了解match语句的使用

  1. 理解变量作用域

Scala提供的控制结构并不算多,因为在 函数式编程 中,可以自己开发出各种功能的控制结构,所以Scala提供的原生控制结构仅仅够用为止。

一、条件表达式

(一)语法格式

if(条件) 值1else 值21

(二)执行情况

  • 条件为真,结果是值1;条件为假,结果是值2。如果if和else的返回结果同为某种类型,那么条件表达式结果也是那种类型,否则就是Any类型

(三)案例演示

任务1、根据输入值的不同进行判断

当然也可以在一个表达式中进行多次判断

可以将上述条件表达式改造成嵌套的选择结构,可读性倒是提高了,但是简洁性降低了

课堂练习:利用选择表达式评定学生成绩等级

  • 函数式编程语言,只有一个入口和一个出口,中间没有任何与外界交流的输入或输出语句,所以安全性非常好。

Java不是函数式语言,选择结构没有返回值,就必须根据不同情况对评语变量赋值。

任务2、编写Scala程序,判断奇偶性

  • 打开Scala项目ScalaDemo,创建net.huawei.day02包,在包里创建Example01对象

packagenet.huawei.day02importscala.io.StdIn

/**
 * 功能:判断奇偶性
 * 作者:华卫
 * 日期:2023年02月22日
 */object Example01 {def main(args: Array[String]):Unit={
    print("n = ")val n = StdIn.readLine.toInt
    if(n %2==0)
      println(n.toString +"是偶数~")else
      println(n.toString +"是奇数~")}}12345678910111213141516171819

运行程序,查看结果

  • 利用if结构具有返回值的特性,改写程序成为函数式风格

packagenet.huawei.day02importscala.io.StdIn

/**
 * 功能:判断奇偶性
 * 作者:华卫
 * 日期:2023年02月22日
 */object Example01 {def main(args: Array[String]):Unit={
    print("n = ")val n = StdIn.readLine.toInt
    val result =if(n %2==0)
      n.toString +"是偶数~"else
      n.toString +"是奇数~"
    println(result)}}1234567891011121314151617181920
  • 运行程序,查看结果

二、块表达式

(一)语法格式

{语句组}1
  • 块表达式为包含在符号“{}”中的语句块

(二)执行情况

  • 需要注意的是,Scala中的返回值是最后一条语句的执行结果,而不需要像Java一样单独写return关键字。如果表达式中没有执行结果,就返回一个Unit对象,类似Java中的void

(三)案例演示

语句块最后一句的值就是整个块表达式的结果

语句块最后一句没有执行结果,那么块表达式结果就是Unit

三、for循环

(一)单重for循环

1、语法格式

for(变量 <- 集合或数组 (条件)){
     语句组
}123

2、执行情况

  • 表示将集合或数组中的每一个值循环赋给一个变量

3、案例演示

任务1:输出1到10

两种方式实现,一种使用Range类,一种使用to运算符

  • Range(a, b): 从a到b,不包含b,跟Python里的range函数一样,含头不含尾

1 to 10表示将1到10的所有值组成一个集合,且包括10。若不想包括10,则可使用关键字until

用Java语言完成任务

用Python语言完成任务

打印字符直角三角形

利用map函数产生每行星号构成的向量,然后利用foreach函数循环输出

利用双重循环与流间变量,这个是Scala语言特有的东西

任务2、遍历字符串,输出每个字符

方法一、按索引取字符串的每个字符(传统for循环)

方法二:将字符串看作一个由多个字符组成的集合(增强for循环)

任务3、计算 1 + 2 + 3 + … + 100
  • 注意sum必须定义为var型变量

  • 利用集合的归并方法来求和最简单

  • 大家有兴趣可以去了解scala集合的聚合函数

任务4、输出列表内的偶数(过滤)

采用三种方法来实现

采用Java语言实现

采用Python语言实现

任务5、输出全部两位素数
for(n <-10 to 100;if!(n %2==0|| n %3==0|| n %5==0|| n %7==0))  print(n.toString +" ")1
(10 to 100).filter(n =>!(n %2==0|| n %3==0|| n %5==0|| n %7==0))1

(二)嵌套for循环

1、语法格式

  • 传统格式

for(变量1<- 集合或数组(条件))
    for(变量2<- 集合或数组(条件)){
       语句组
    }}12345
  • 特有格式

for(变量1<- 集合或数组; 变量2<- 集合或数组 (条件)){
   语句组
}123

2、案例演示

任务1、打印九九表
方法一、采用双重循环来实现
  • net.huawei.day02包里创建Example02对象

packagenet.huawei.day02/**
 * 功能:双重循环打印九九表
 * 作者:华卫
 * 日期:2023年02月22日
 */object Example02 {def main(args: Array[String]):Unit={for(i <-1 to 9){for(j <-1 to i){
        print(i.toString +"×"+ j +"="+(i * j)+"\t")}
      println()}}}1234567891011121314151617
  • 运行程序,查看结果

方法二、采用单重循环来实现
  • net.huawei.day02包里创建Example03对象

packagenet.huawei.day02/**
 * 功能:单重循环打印九九表
 * 作者:华卫
 * 日期:2023年02月22日
 */object Example03 {def main(args: Array[String]):Unit={for(i <-1 to 9; j <-1 to i){
      print(i.toString +"×"+ j +"="+(i * j)+"\t")if(j == i) println()}}}123456789101112131415
  • 运行程序,查看结果

方法三、采用单重循环与流间变量绑定来实现
  • net.huawei.day02包里创建Example04对象

  • 在for循环头里sep = if (i == j) "\n" else "\t"就是流间变量绑定

packagenet.huawei.day02/**
 * 功能:单重循环与流间变量绑定打印九九表
 * 作者:华卫
 * 日期:2023年02月22日
 */object Example04 {def main(args: Array[String]):Unit={for(i <-1 to 9; j <-1 to i; sep =if(j == i)"\n"else"\t"){
      print(i.toString +"×"+ j +"="+(i * j)+ sep)}}}1234567891011121314
  • 运行程序,查看结果

方法四、采用单重循环、流间变量与yield来实现
  • for循环语句本身的返回值是Unit类型,无论在循环体中返回什么都是无效的,最终得到的都是Unit的值,但是可以在循环中的循环条件和循环体之间加上yield关键字,那么就可以将循环体产生的返回值组成数组进行返回。

  • net.huawei.day02包里创建Example05对象

packagenet.huawei.day02/**
 * 功能:采用单重循环、流间变量与yield打印九九表
 * 作者:华卫
 * 日期:2023年02月22日
 */object Example05 {def main(args: Array[String]):Unit={val list =for(i <-1 to 9; j <-1 to i; sep =if(j == i)"\n"else"\t")yield i.toString +"×"+ j +"="+(i * j)+ sep
    list.foreach(print)}}1234567891011121314
  • 运行程序,查看结果

任务2、去掉对角线
  • 一个三阶方阵,单元格的值是行号与列号的乘积,去掉对角线,输出剩余元素

  • 方法一、传统双重循环

packagenet.huawei.day02/**
 * 功能:去掉对角元素
 * 作者:华卫
 * 日期:2023年02月22日
 */object Example06 {def main(args: Array[String]):Unit={for(i <-1 to 3){for(j <-1 to 3){if(i != j)
          print((i * j).toString +"\t")else
          print("\t")}
      println()}}}1234567891011121314151617181920
  • 运行程序,查看结果

  • 方法二、特有双重循环

packagenet.huawei.day02/**
 * 功能:去掉对角线元素
 * 作者:华卫
 * 日期:2023年02月22日
 */object Example07 {def main(args: Array[String]):Unit={for(i <-1 to 3; j <-1 to 3; sep =if(i == j)"\t"else(i * j).toString +"\t"){
      print(sep)if(j ==3) println()}}}123456789101112131415
  • 运行程序,查看结果

  • 方法三:采用两个流间变量和yield

packagenet.huawei.day02/**
 * 功能:去掉对角线元素
 * 作者:华卫
 * 日期:2023年02月22日
 */object Example08 {def main(args: Array[String]):Unit={val list =for(i <-1 to 3; j <-1 to 3; sep =if(j==3)"\n"else"\t";
                    str =if(i != j)(i * j).toString + sep else" "+ sep)yield str
    list.foreach(print)}}1234567891011121314
  • 运行程序,查看结果

课堂练习:编程求解百钱买百鸡问题
  • 我国古代数学家张丘建在《算经》一书中曾提出过著名的“百钱买百鸡”问题,该问题叙述如下:鸡翁一,值钱五;鸡母一,值钱三;鸡雏三,值钱一;百钱买百鸡,则翁、母、雏各几何?

翻译过来,意思是公鸡一个五块钱,母鸡一个三块钱,小鸡三个一块钱,现在要用一百块钱买一百只鸡,问公鸡、母鸡、小鸡各多少只?

{ c o c k + h e n + c h i c k = 100 ( 1 ) c o c k × 5 + h e n × 3 + c h i c k 3 = 100 ( 2 )

⎧⎩⎨cock+hen+chick=100cock×5+hen×3+chick3=100(1)(2){����+ℎ��+�ℎ���=100(1)����×5+ℎ��×3+�ℎ���3=100(2)

⎩⎨⎧cock+hen+chick=100cock×5+hen×3+3chick=100(1)(2)

四、条件循环

(一)while循环

1、语法格式

  • Scala的while循环与Java类似

while(条件){   
   循环体
}123

2、案例演示

任务1、计算1+ 2 + 3 + … + 100
  • 注意:sum必须是变量

  • 采用函数式风格来写代码,递归函数来实现求和,注意:此处sum是常量

任务2、打印全部水仙花数
  • 所谓水仙花数,是指等于其各位数字立方和的三位数。

\qquad153 = 1 3 + 5 3 + 3 3 153=1^3+5^3+3^3153=13+53+33

\qquad370 = 3 3 + 7 3 + 0 3 370=3^3+7^3+0^3370=33+73+03

\qquad371 = 3 3 + 7 3 + 1 3 371=3^3+7^3+1^3371=33+73+13

\qquad407 = 4 3 + 0 3 + 7 3 407=4^3+0^3+7^3407=43+03+73

  • 对于[100, 999]范围的每个数n,我们要去判断它是否等于其各位数字的立方和,这里的难点或关键在于如何分解一个三位数,得到它的每位数字。

  • 假设我们已经把三位数n分解成百位数p3,十位数p2,个位数p1,
    这样我们的筛选条件就可以写出来:n == p3 * p3 * p3 + p2 * p2 * p2 + p1 * p1 * p1。

  • 如何拆分一个三位数n呢?

  • 首先求n的个位数:n % 10
    然后要将三位数变成两位数:n = n / 10;
    对于新的两位数n,又求它的个位数:n % 10
    然后要将两位数变成一位数:n = n / 10;

  • 也就是说我们可以交替使用求余和整除运算将一个三位数拆分,得到它的个位数、十位数和百位数。当然这个分解方法可以推广到任何多位数的拆分。

net.hw.structure包里创建Example06对象

packagenet.hw.structure/**
  * 功能:打印水仙花数
  * 作者:华卫
  * 日期:2022年03月06日
  */object Example06 {def main(args: Array[String]):Unit={for(n <-100 to 999){val p1 = n %10// 个位数val p2 = n /10%10// 十位数val p3 = n /100// 百位数if(n == p1 * p1 * p1 + p2 * p2 * p2 + p3 * p3 * p3)
        println(n.toString +" = "+ p3 +"^3 + "+ p2 +"^3 + "+ p1 +"^3")}}}123456789101112131415161718
  • 运行程序,查看结果

(二)do while循环

  • 与Java语言一样,do while循环与while循环类似,但是do while循环会确保至少执行一次循环。

1、语法格式

do{
   循环体
}while(条件)123

2、案例演示

任务:计算1+ 2 + 3 + … + 100

五、异常处理

(一)异常处理概述

  • Scala中继承了Java的异常机制,提供了程序中产生意外情况时处理的机制,抛出异常的过程和Java中基本一致,通过throw关键字进行:throw XxxException(),一旦抛出可以当场捕获处理或接着向上抛,捕获异常是通过 try-catch-finally来实现的。

(二)案例演示

任务:演示try-catch-finally

  • try-catch是有返回值的:如果没有异常就是try语句的返回值,如果有异常就是catch语句的返回值。注意不会是finally的返回值,finally即使有返回值,也会被抛弃,这点和Java是不同的。

  • net.hw.structure包里创建Example07对象

packagenet.hw.structureimportjava.io.IOException

/**
  * 功能:演示异常处理
  * 作者:华卫
  * 日期:2022年03月06日
  */object Example07 {def main(args: Array[String]):Unit={var message =""val result =try{
      mx()"恭喜,程序执行正常!"}catch{case e: NullPointerException =>"空指针异常"case e: IOException =>"呵呵,I/O异常~"case e: Exception =>"管它呢,反正是异常~"}finally{
      message ="程序到此为止!""无论是否有异常,都会执行finally里的语句~"}
    println(result)
    println(message)}def mx():Unit={thrownew RuntimeException("随便抛出一个异常~")}}12345678910111213141516171819202122232425262728293031

执行程序,查看结果(此时有异常,result取的是catch里的返回值 - 管它呢,反正是异常~,finally语句块执行了的,因此message可以打印出来 - 程序到此为止!

注释掉mx()方法里的语句

执行程序,查看结果(此时有异常,result取的是try里的返回值 - 恭喜,程序执行正常!

在Scala里,finally的返回值不会覆盖try和catch的返回值,这一点跟Java不同。

运行程序,查看结果(此时运行test()方法,调用mx()方法抛出异常,执行catch语句块,返回异常~,但是要被finally语句块的返回值停止!覆盖,因此最终输出的就是停止!

我们把mx()方法里的抛出异常的语句注释掉,此时程序正常运行,但是test()方法的返回值不会是正常~,还是会被finally语句块的返回值覆盖,成为停止!

六、match结构

(一)语法格式

变量 match{case 值1=> 表达式1或语句1case 值2=> 表达式2或语句2case 值3=> 表达式3或语句3
      ……
      case _ => 表达式n或语句n
    }1234567
  • Scala中的match类似于其他语言的switch。与Java不同的是,match语句可以应用在任何类型量或表达式上,另外需要调用break语句,match默认执行完一个case后直接跳出match结构。注意,match是具有返回值的,就是被选到的case的值。

(二)案例演示

任务:给城市下评语

  • net.hw.structure包里创建Example08对象

packagenet.hw.structureimportscala.io.StdIn

/**
  * 功能:演示match语句
  * 作者:华卫
  * 日期:2022年03月06日
  */object Example08 {def main(args: Array[String]):Unit={
    print("输入城市:")val city = StdIn.readLine();val comment = city match{case"北京"=>"伟大的首都"case"上海"=>"神奇的魔都"case"泸州"=>"醉人的酒城"case _ =>"一般的城市"}
    print(city +": "+ comment)}}12345678910111213141516171819202122
  • 运行程序,查看结果

七、变量作用域

(一)Java变量作用域

  • Java中根据不同大括号区分变量作用范围,不允许有叠加,外部看不到内部,内部能看到外部。

1、内部能访问外部

2、外部不能看内部

(二)Scala变量作用域

  • Scala中根据不同大括号区分变量作用范围,不允许有叠加,外部看不到内部,内部看不到外部。

1、内部不能访问外部

  • net.hw.structure包创建Example09对象

2、外部不能访问内部

  • net.hw.structure包创建Example10对象

八、补充案例

任务:评定成绩等级

1、编写符合函数式编程风格的Sala程序

  • net.hw.structure包里创建Example11对象

packagenet.hw.structureimportscala.io.StdIn

/**
  * 功能:判定成绩等级(函数式风格)
  * 作者:华卫
  * 日期:2022年03月06日
  */object Example11 {def main(args: Array[String]):Unit={
    print("score = ")val score = StdIn.readLine().toInt

    val comment =if(score >100){"超出范围"}elseif(score >=90){"优秀"}elseif(score >=80){"良好"}elseif(score >=70){"中等"}elseif(score >=60){"及格"}elseif(score >=0){"不及格"}else{"超出范围"}

    println("评语:"+ comment)}}123456789101112131415161718192021222324252627282930313233
  • 运行程序,查看结果

2、函数式风格的程序有几个特点

  • if结构像函数一样有返回值

  • if结构里除了传入参数score之外,没有别的变量。
    -if结构里没有与外界交流,比如输入或输出或网络连接或读取文件之类。

  • 函数式编程是为了处理计算,不考虑系统的读写(I/O)。

  • 函数式编程强调没有副作用(指的是函数内部与外部互动,产生运算以外的其它结果)。函数要求独立,只返回一个值,没有其它行为,尤其不能修改外部变量的值。

3、非函数式风格的程序

看看下面这个程序 - Example12

  • 虽然处理结果跟上面那个程序一样,但是并不符合函数式编程风格。因为if结构有副作用,修改了if结构之外的变量comment的值。

再看看下面这个程序 - Example13

  • 不符合函数式编程风格。因为if结构有副作用,有写操作。e

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值