尚硅谷Scala(1-5)

一、Scala 概述

1.1.1 Scala 程序反编译-说明 scala 程序的执行流程

//package com.atguigu.chapter01
//下面我们说明一下 scala 程序的一执行流程
//分析
//1. object 在底层会生成两个类 Hello , Hello$
//2. Hello 中有个 main 函数,调用 Hello$ 类的一个静态对象 MODULES$
/*
public final class Hello
{
public static void main(String[] paramArrayOfString)
{
Hello$.MODULE$.main(paramArrayOfString);
}
}
*/
//3. Hello$.MODULE$. 对象时静态的,通过该对象调用 Hello$的 main 函数
/*
public void main(String[] args)
{
Predef..MODULE$.println("hello,scala");
}
*/
//4. 可以理解我们在 main 中写的代码在放在 Hello$ 的 main, 在底层执行 scala 编译器做了一个包
装
object Hello {
def main(args: Array[String]): Unit = {
println("hello,scala")
}
}

1.1.2 使用 java 写了一段模拟的代码

package com.atguigu.chapter01;
public class Hello2 {
public static void main(String[] args) {
Hello2$.MODULE$.main(args);
}
}
final class Hello2$
{
public static final Hello2$ MODULE$;
static
{
MODULE$ = new Hello2$();
}
public void main(String[] args)
{
System.out.println("hello,scala");
}
//private Hello$() { MODULE$ = this; }

1.1.3 Scala 执行流程分析

 1.1.4 Scala 语言输出的三种方式

1) 字符串通过 + 号连接(类似 java
2) printf 用法 (类似 C 语言)字符串通过 % 传值
3) 字符串通过 $ 引用 ( 类似 PHP
package org.example.chaapter01

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 =18
    var sal:Float=10.67f
    var height:Double=180.12

    //格式化输出
    printf("名字=%s 年龄是=%d 薪水%.2f 身高%.2f",name,age,sal,height)

    //scala支持使用$输出内容
    println(s"\n个人信息如下:\n名字$name \n年龄$age \n薪水$sal")
    //如果在字符串中出现了类似${age+10},则表示{}是一个表达式
    println()
    println(s"\n个人信息如下:\n名字${name} \n年龄${age+10} \n薪水${sal}")
  }

}

结果如下:

hello world
名字=Tom 年龄是=18 薪水10.67 身高180.12
个人信息如下:
名字Tom 
年龄18 
薪水10.67


个人信息如下:
名字Tom 
年龄28 
薪水10.67

二、变量

2.1 变量的介绍

2.1.1 概念

        变量相当于内存中一个数据存储空间的表示,你可以把变量看做是一个房间的门牌号,通过门牌号我们可以找到房间,而通过变量名可以访问到变量(值)。

2.1.2 变量使用的基本步骤

1) 声明 / 定义变量 (scala 要求变量声明时初始化 )
2) 使用

2.2 scala 变量的基本使用

2.2.1 快速入门

object VarDemo01 {
  def main(args: Array[String]): Unit = {
    var name:String ="hsw"
    var age:Int =18
    var sal:Double=10.9
    var isPass:Boolean=true
    //在scala中,小数默认为Double,整数默认为Int
    var score:Float=80.2f
    println(s"${name} ${isPass}")
  }

}

2.3 Scala 变量使用说明

2.3.1 变量声明基本语法

var | val 变量名 [: 变量类型 ] = 变量值

2.3.2 注意事项

1) 声明变量时,类型可以省略(编译器自动推导,即类型推导)

2) 类型确定后,就不能修改,说明 Scala 是强数据类型语言

3) 在声明/定义一个变量时,可以使用 var 或者 val 来修饰, var 修饰的变量可改变,val 修饰的变量不可改 

4) val 修饰的变量在编译后,等同于加上 final, 通过反编译看下底层代码。

5) var 修饰的对象引用可以改变,val 修饰的则不可改变,但对象的状态()却是可以改变的。(比 如: 自定义对象、数组、集合等等)

6) 变量声明时,需要初始值

object VarDemo02 {
  def main(args: Array[String]): Unit = {
    //1)类型推导
    var num=10
    //方式 1,可以利用 idea 的提示来证明,给出提示
    //方式 2,使用 isInstanceOf[Int]判断
    println(num.isInstanceOf[Int])

    //2)类型确定后,就不能修改,说明 Scala 是强数据类型语言()
    //num=2.3  错误

    //3)在声明/定义一个变量时,可以使用 var 或者 val 来修饰, var 修饰的变量可改变,val 修饰的变量不可改
    var age =10
    age=30 //ok

    val num2=30
    //num2=40  val 修饰的变量是不可变的

    //scala 设计者为什么设计 var 和 val
    //(1) 在实际编程,我们更多的需求是获取/创建一个对象后,读取该对象的属性,
    // 或者是修改对象的属性值, 但是我们很少去改变这个对象本身
    // dog = new Dog() dog.age = 10 dog = new Dog()
    // 这时,我们就可以使用 val
    //(2) 因为 val 没有线程安全问题,因此效率高,scala 的设计者推荐我们 val
    //(3) 如果对象需要改变,则使用 var

    val dog = new Dog()
    dog.age=2
    dog.name="小猪"
    println("dog的名字为:"+dog.name)


  }
}

class Dog{
  //声明一个age属性,给了一个默认值_
  var age:Int =0
  var name:String=""
}
4) val 修饰的变量在编译后,等同于加上 final,通过反编译看下底层代码。

object VarDemo03 {
var name = "hello"
val age = 100
def main(args: Array[String]): Unit = {
println("ok")
}
}

对应的底层的反编译的代码
public final class VarDemo03$
{
public static final MODULE$;
private String name;
private final int age;
}

2.4 程序中 +号的使用

1) 当左右两边都是数值型时,则做加法运算
2) 当左右两边有一方为字符串,则做拼接运算

2.5 数据类型

1) Scala 与 Java 有着相同的数据类型,Scala 中数据类型都是对象,也就是说 scala 没有 java 中的原生类型

2) Scala 数据类型分为两大类 AnyVal(值类型) AnyRef(引用类型), 注意:不管是 AnyVal 还 是 AnyRef 都是对象。[案例演示 Int , Char]

3) 相对于 java 类型系统 scala 复杂些 !也正是这复杂多变的类型系统才让面向对象编程和函数式编程完美的融合在了一起
object TypeDemo01 {
  def main(args: Array[String]): Unit = {
    var num1:Int =10
    //因为 Int 是一个类,因此他的一个实例,就是可以使用很多方法
    //在 scala 中,如果一个方法,没有形参,则可以省略()
    println(num1.toDouble+"\t"+num1.toString+"\t"+100.toDouble)

    var isPass = true
    println(isPass.toString)
  }
}

2.5.1 scala 数据类型体系一览图

  对上面图的小结和整理

1) scala 中有一个根类型 Any , 他是所有类的父类 .
2) scala 中一切皆为对象,分为两大类 AnyVal( 值类型 ) AnyRef( 引用类型 ) , 他们都是 Any 子类 .
3) Null 类型是 scala 的特别类型,它只有一个值 null, 他是 bottom calss , 是 所有 AnyRef 类型的子
.
4) Nothing 类型也是 bottom class , 他是所有类的子类,在开发中通常可以将 Nothing 类型的值返回给任意变量或者函数, 这里抛出异常使用很多.
object TypeDemo02 {
  def main(args: Array[String]): Unit = {
    println(sayHello)

  }

  //比如开发中,我们有一个方法,就会异常中断,这时久可以返回Nothing
  //及当我们Nothing做返回值,就是明确说明该方法没有正常返回值
  def sayHello: Nothing ={
    throw new Exception("抛出异常")
  }
}
5) scala 中仍然遵守,低精度的值,向高精度的值自动转换 (implicit conversion) 隐式转换
    var num=1.2
    var num2=1.7f
    //修改类型
    num2=num.toFloat

2.5.2 scala 数据类型列表

2.6 整数类型

2.6.1基本介绍

Scala 的整数类型就是用于存放整数值的,比如 12 , 30, 3456 等等

2.6.2 整型的类型

2.6.3 整型的使用细节 

1) Scala 各整数类型有固定的表数范围和字段长度,不受具体 OS 的影响,以保证 Scala 程序的可
移植性。
2) Scala 的整型 常量 / 字面量 默认为 Int 型,声明 Long 型 常量 / 字面量 须后加‘
l ’’或‘L’
3) Scala 程序中变量常声明为  Int 型,除非不足以表示大数,才使用 Long

2.7 浮点类型

2.7.1 基本介绍

Scala 的浮点类型可以表示一个小数,比如 123.4f 7.8 0.12 等等

2.7.2 浮点型的分类

 2.7.3 浮点数的使用细节

1) 与整数类型类似, Scala 浮点类型也有固定的表数范围和字段长度,不受具体 OS 的影响。
2) Scala 的浮点型常量默认为 Double 型,声明 Float 型常量,须后加f’或‘F’。
3) 浮点型常量有两种表示形式
十进制数形式:如:5.12   512.0f    .512     (必须有小数点)
科学计数法形式 : 如: 5.12e2 = 5.12 乘以 10 2 次方
                                 5.12E-2 = 5.12 除以 10 的 2 次方
4) 通常情况下,应该使用 Double 型,因为它比 Float 型更精确 ( 小数点后大致 7 )
// 测试数据 : 2.2345678912f , 2.2345678912

2.8 字符类型(Char)

2.8.1 基本介绍

字符类型可以表示单个字符 , 字符类型是 Char 16 位无符号 Unicode 字符 (2 个字节 ), 区间值为
U+0000 U+FFFF

2.8.2 字符类型使用细节

1) 字符常量是用单引号 ( ‘ ’ ) 括起来的单个字符。例如: var c1 = 'a var c2 = ' 中‘ var c3 = '9'
2) Scala 也允许使用转义字符‘\’来将其后的字符转变为特殊字符型常量。例如: var c3 = ‘\n’
// '\n' 表示换行符
3) 可以直接给 Char 赋一个整数,然后输出时,会按照对应的 unicode 字符输出 ['\u0061' 97]
4) Char 类型是可以进行运算的,相当于一个整数,因为它都对应有 Unicode .

2.9 布尔类型:Boolean

2.9.1 基本介绍

布尔类型也叫 Boolean 类型, Booolean 类型数据只允许取值 true false
boolean 类型占 1 个字节。
boolean 类型适于逻辑运算,一般用于程序流程控制
        if 条件控制语句;
        while 循环控制语句;
        do-while 循环控制语句;
        for 循环控制语句

2.10 Unit 类型、Null 类型和 Nothing 类型

2.10.1 基本说明

2.10.2 使用细节的案例 

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 是其他任意类型的子类,他还能跟要求返回值的方法兼容。
object UnitNullNothingDemo {
  def main(args: Array[String]): Unit = {
    val res=sayHello()
    println("res:"+res)


    //Null类只有一个实例对象,null,类似于Java中的null引用。null可以赋值给任意引用类型(AnyRef),
    //但是不能赋值给值类型(AnyVal: 比如 Int, Float, Char, Boolean, Long, Double, Byte, Short)
    var dog:Dog =null
    //var char1:Char=null  报错
    println("ok")
  }

  //Unit 等价于 java 的 void,只有一个实例值()
  def sayHello(): Unit ={

  }
}

class Dog{

}

2.11 值类型转换

2.11.1 值类型隐式转换

介绍
Scala 程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数据类型,这个就是自动
类型转换 ( 隐式转换 )
数据类型按精度 ( 容量 ) 大小排序为

2.11.2 值类型隐式转换

自动类型转换细节说明
1) 有多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的那种数据类型,然
后再进行计算。 5.6 + 10 = double
2) 当我们把精度 ( 容量 ) 大 的数据类型赋值给精度 ( 容量 ) 小 的数据类型时,就会报错,反之就会进
行自动类型转换。
3) (byte, short) char 之间不会相互自动转换。
4) byte short char 他们三者可以计算,在计算时首先转换为 int 类型。
5) 自动提升原则: 表达式结果的类型自动提升为 操作数中最大的类型

2.11.3 高级隐式转换和隐式函数

2.11.4 强制类型转换

介绍
        自动类型转换的逆过程 ,将容量大的数据类型转换为容量小的数据类型。使用时要加上强制转函 数,但可能造成精度降低或溢出, 格外要注意。
案例演示
java : int num = (int)2.5
scala : var num : Int = 2.7.toInt // 对象
强制类型转换细节说明
1) 当进行数据的 从 大—— > 小,就需要使用到强制转换
2) 强转符号只针对于 最近的操作数有效 ,往往会 使用小括号提升优先
3) Char 类型可以保存 Int 的常量值,但不能保存 Int 的变量值,需要强转
4) Byte Short 类型在进行运算时,当做 Int 类型处理。
object Demo02 {
  def main(args: Array[String]): Unit = {
    val num1:Int =10*3.5.toInt+6*1.6.toInt //36
    val num2:Int =(10*3.5+6*1.6).toInt  //44
    println(num1)
    println(num2)

    val char1:Char=1
    val num3=1
    //val char2:Char =num3  错误
  }
}

2.12 值类型和 String 类型的转换

2.12.1 介绍

在程序开发中,我们经常需要将基本数据类型转成 String 类型。
或者将 String 类型转成基本数据类型。

2.12.2 基本类型转 String 类型

语法: 将基本类型的值 +"" 即可
案例演示
val d1 = 1.2
// 基本数据类型转 string
val s1 = d1 + "" // 以后看到有下划线,就表示编译器做了转换

2.12.3 String 类型转基本数据类型

object Demo03 {
  def main(args: Array[String]): Unit = {
    val d1 = 1.2
    //基本数据类型转String类型
    val s1 = d1 + "" //以后看到下划线,就表示编译器做了转换

    //String类型转基本数据类型
    val s2="252"
    val num1=s2.toInt
    val num2=s2.toDouble
    val num3=s2.toLong
    val num4=s2.toByte

    println("ok")

    //1) 在将 String 类型转成 基本数据类型时,要确保 String 类型能够转成有效的数据,比如 我们可
    //以把 "123" , 转成一个整数,但是不能把 "hello" 转成一个整数
    val s3="hello"
    println(s3.toInt) //会报异常

    //2) 思考就是要把 "12.5" 转成 Int //?
    //在 scala 中,不是将小数点后的数据进行截取,而是会抛出异常
    val s4="12.5"
    val num5=s4.toInt //error
    val num6=s4.toDouble  //ok
    println(num5)
  }
}

2.13 标识符的命名规范

2.13.1 标识符概念

1) Scala 对各种变量、方法、函数等命名时使用的字符序列称为标识符
2) 凡是自己可以起名字的地方都叫标识符

2.13.2 标识符的命名规则

1) Scala 中的标识符声明,基本和 Java 是一致的,但是细节上会有所变化。
2) 首字符为字母,后续字符任意字母和数字,美元符号,可后接下划线 _
3) 数字不可以开头。
4) 首字符为操作符 ( 比如 + - * / ) ,后续字符也需跟操作符 , 至少一个 ( 反编译 )
5) 操作符 ( 比如 +-*/) 不能在标识符中间和最后 .
6) 用反引号 `....` 包括的任意字符串,即使是关键字 (39 ) 也可以 [true]
object IdenDemo01 {
def main(args: Array[String]): Unit = {
//首字符为操作符(比如+ - * / ),后续字符也需跟操作符 ,至少一个
val ++ = "hello,world!" println(++)
val -+*/ = 90 //ok
println("res=" + -+*/)
//看看编译器怎么处理这个问题
// ++ => $plus$plus
//val +q = "abc" //error
//用反引号`....`包括的任意字符串,即使是关键字(39 个)也可以
var `true` = "hello,scala!" println("内容=" + `true`)
val Int = 90.45
println("Int=" + Int)
//不能使用_ 做标识符
var _ = "jack" println(_)

2.13.3 标识符命名注意事项

1) 包名:尽量采取有意义的包名,简短,有意义
2) 变量名、函数名 、方法名 采用驼峰法。

2.13.4 scala 的关键字 39

Scala 39 个关键字:
package, import, class, object, trait, extends, with, type, forSome
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

三、运算符

3.1 运算符介绍

运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。
1) 算术运算符
2) 赋值运算符
3) 比较运算符 ( 关系运算符 )
4) 逻辑运算符
5) 位运算符

3.2 算术运算符

3.2.1 介绍

算术运算符 (arithmetic) 是对数值类型的变量进行运算的,在 Scala 程序中使用的非常多。

3.2.2 算术运算符的一览图

3.2.3 细节说明

1) 对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法时,只保留整数部分而舍弃
小数部分。 例如: var x : Int = 10/3 , 结果是 3
2) 当对一个数取模时,可以等价 a%b=a-a/b*b , 这样我们可以看到取模的一个本质运算 ( java
的取模规则一样 )
3) 注意: Scala 中没有 ++ -- 操作符,需要通过 += -= 来实现同样的效果

3.3 关系运算符(比较运算符)

3.3.1 基本介绍

1) 关系运算符的结果都是 boolean 型,也就是要么是 true ,要么是 false
2) 关系表达式 经常用在 if 结构的条件中或循环结构的条件中
3) 关系运算符的使用和 java 一样

3.3.2 关系运算符的一览图

3.3.3案例演示

var a = 9
var b = 8
println(a>b) // true
println(a>=b) // true
println(a<=b) // false
println(a<b) // false
println(a==b) // false
println(a!=b) // true
var flag : Boolean = a>b // true

3.3.4 细节说明

1 .关系运算符的结果都是 Boolean 型,也就是要么是 true ,要么是 false
2 .关系运算符组成的表达式,我们称为关系表达式。 a > b
3 .比较运算符“ == ”不能误写成“ =
4 .使用陷阱 : 如果两个浮点数进行比较,应当保证数据类型一致 .

3.4 逻辑运算符

3.4.1 介绍

用于连接多个条件(一般来讲就是关系表达式),最终的结果也是一个 Boolean

3.4.2 逻辑运算符的一览图和案例

3.5 赋值运算符

3.5.1介绍

赋值运算符就是将某个运算后的值,赋给指定的变量。

3.5.2 赋值运算符的分类

3.5.3 赋值运算符特点 

1) 运算顺序从右往左
2) 赋值运算符的左边 只能是变量 , 右边 可以是变量、表达式、常量值 / 字面量
3) 复合赋值运算符等价于下面的效果
比如: a+=3 等价于 a=a+3

3.5.4 位运算符

3.5.5 Scala 不支持三目运算符 , Scala 中使用 if else 的方式实现

val num = 5 > 4 ? 5 : 4 // 没有
val num = if (5>4) 5 else 4
案例 1 :求两个数的最大值
案例 2 :求三个数的最大值
object Demo01 {
def main(args: Array[String]): Unit = {
val num = if (5 > 4) 5 else 4
//val num2 = 5 > 4 ? 5 : 4 错误
/**
* 案例 1:求两个数的最大值
* 案例 2:求三个数的最大值
*
*/
val n1 = 4
val n2 = 8
var res = if (n1 > n2) n1 else n2
println("res=" + res)
val n3 = 11
res = if (res > n3) res else n3
println("res=" + res)
}
}

3.6 运算符优先级

1) 运算符有不同的优先级,所谓优先级就是表达式运算中的运算顺序。如右表,上一行运算符总
优先于下一行。
2) 只有单目运算符、赋值运算符是从右向左运算的。
3) 运算符的优先级和 Java 一样。
小结运算符的优先级
1.() []
2. 单目运算
3. 算术运算符
4. 移位运算
5. 比较运算符 ( 关系运算符 )
6. 位运算
7. 关系运算符
8. 赋值运算
9.,

3.6.1运算符优先级的一览图

3.7 键盘输入语句 

3.7.1介绍

在编程中,需要接收用户输入的数据,就可以使用键盘输入语句来获取。 InputDemo.scala

3.7.2案例演示

object Demo01 {
  def main(args: Array[String]): Unit = {
    /*
    要求:可以从控制台接收用户信息,【姓名,年龄,薪水】
*/
    print("请输入姓名:")
    val name =StdIn.readLine()
    print("请输入年龄:")
    val age =StdIn.readInt()
    print("请输入工资:")
    val sal =StdIn.readDouble()

    printf("用户的信息为: name=%s age=%d sal=%f",name,age,sal)

    Cat.sayHi()

  }
}

//声明一个对象(伴生对象)
object Cat{
  //方法
  def sayHi(): Unit ={
    println("小猫小猫!")
  }
}

四、程序流程控制

4.1 程序的流程控制说明

        在程序中,程序运行的流程控制决定程序是如何执行的,是我们必须掌握的,主要有三大流程控制语句。
温馨提示 Scala 语言中控制结构和 Java 语言中的控制结构基本相同,在不考虑特殊应用场景的
情况下,代码书写方式以及理解方式都没有太大的区别
  1.  顺序控制
  2. 分支控制
  3. 循环控制

4.2 顺序控制的说明

4.3 分支控制 if-else

4.3.1分支控制 if-else 介绍

让程序有选择的的执行 , 分支控制有三种 :
1) 单分支
2) 双分支
3) 多分支

4.3.2单分支的使用

4.3.3 双分支 

 案例:

/*4) 判断一个年份是否是闰年,闰年的条件是符合下面二者之一:(1)年份能被 4 整除,但不能被 100整除;(2)能被 400 整除*/
object Exercise01 {
  def main(args: Array[String]): Unit = {
    print("请输入一个年份:")
    val year=StdIn.readInt()
    if((year%4==0) && (year%100!=0)){
      printf("%d年是润年",year)
    }else{
      printf("%d不是润年",year)
    }
  }

}

4.3.6 多分支

案例演示:

object ifelsesDemo03 {
def main(args: Array[String]): Unit = {
/*
岳小鹏参加 scala 考试,他和父亲岳不群达成承诺:
如果:
成绩为 100 分时,奖励一辆 BMW;
成绩为(80,99]时,奖励一台 iphone7plus;
当成绩为[60,80]时,奖励一个 iPad;
其它时,什么奖励也没有。
成绩是从控制台输入
*/
println("请输入成绩")
val score = StdIn.readDouble()
if (score == 100) {
println("成绩为 100 分时,奖励一辆 BMW")
} else if (score > 80 && score <= 99) { //写法 1 使用范围,写法 2 就是严格的判断
println("成绩为(80,99]时,奖励一台 iphone7plus")
} else if (score >= 60 && score <= 80) {
println("奖励一个 iPad")
} else {
println("没有任何奖励")
}
}
}

4.3.7 分支控制 if-else 注意事项

1) 如果大括号 {} 内的逻辑代码只有一行,大括号可以省略 , 这点和 java 的规定一样。
2) Scala 中任意表达式都是有返回值的,也就意味着 if else 表达式其实是有返回结果的,具体返回
结果的值取决于满足条件的代码体的最后一行内容 .[ 案例演示 ]
3) Scala 中是没有三元运算符,因为可以这样简写

4.4 嵌套分支

4.4.1基本介绍

一个分支结构中又完整的嵌套了另一个完整的分支结构 ,里面的分支的结构称为内层分支外面
的分支结构称为外层分支。嵌套分支不要超过 3

4.4.2基本语法

if(){
        if(){
        }else{
        }
}

4.4.3 应用案例

/*
参加百米运动会,如果用时 8 秒以内进入决赛,否则提示淘汰。并且根据性别提示进入男子
组或女子组。输入成绩和性别,进行判断。
*/
object Exercise02 {
  def main(args: Array[String]): Unit = {
    print("请输入运动员的成绩:")
    val speed=StdIn.readDouble()
    if(speed<=8){
      print("请输入性别:")
      val gender=StdIn.readChar()
      if(gender=='男'){
        printf("该运动员进入%c子组",gender)
      }else{
        printf("该运动员进入%c子组",gender)
      }
    }else{
      print("你被淘汰了")
    }
  }
}

4.5 switch 分支结构

scala 中没有 switch, 而是 使用模式匹配来处理
match-case

4.6 for 循环控制

4.6.1基本介绍

Scala 也为 for 循环这一常见的控制结构提供了非常多的特性,这些 for 循环的特性被称为 for
导式 (for comprehension)或 for 表达式 (for expression)

4.6.2 范围数据循环方式 1

说明
i 表示循环的变量, <- 规定好 to 规定
i 将会从 1-3 循环, 前后闭合
object Demo01 {
  def main(args: Array[String]): Unit = {
    //输出10句 hello world!
    for(i <- 1 to 10){
      println("hello world!")
    }
  }

  println()
  //说明 for 这种推导时,也可以直接对集合进行遍历
  val list=List("hello",10,50,"world")
  for(n <- list){
    println("n="+n)
  }
}


//结果:
//n=hello
//n=10
//n=50
//n=world
//hello world!
//hello world!
//hello world!
//hello world!
//有10条

4.6.3 范围数据循环方式 2

说明 :
1) 这种方式和前面的区别在于 i 是从 1 3-1
2) 前闭合后开的范围 , java arr.length() 类似
for (int i = 0; i < arr.lenght; i++){}
object ForUntilDemo02 {
def main(args: Array[String]): Unit = {
//输出 10 句 "hello,world!" val start = 1
val end = 11
//循环的范围是 start --- (end-1)
for (i <- start until end) {
println("hello, world!" + i)

4.6.4 循环守卫

基本案例说明
循环守卫,即循环保护式(也称条件判断式,守卫)。保护式为 true 则进入循环体内部,为 false
则跳过,类似于 continue
object Demo03 {
  def main(args: Array[String]): Unit = {
    for(i <- 1 to 3 if i != 2) {
      print(i + " ") //1 3
    }
    println()
  }
}

4.6.5 引入变量

说明
没有关键字,所以范围后一定要加;来隔断逻辑

object Demo04 {
  def main(args: Array[String]): Unit = {
    for(i <- 1 to 3;j=4-i){
      println(j)
    }
  }
}

4.6.6 嵌套循环

说明
没有关键字,所以范围后一定要加;来隔断逻辑
object Demo05 {
  def main(args: Array[String]): Unit = {
//打印9*9乘法表
    //方法一
//   for(i <- 1 to 9){
//     for(j <- 1 to i){
//       print(s"$j*$i=${i*j}\t")
//     }
//     println()
//   }
//  }

    //简写
    for(i<- 1 to 9;j<- 1 to i) {
      print(s"$i*$j=${i * j} \t")
      if (j == 1) println()
    }
    }
}

 4.6.7 循环返回值

说明
将遍历过程中处理的结果返回到一个新 Vector 集合中,使用 yield 关键字
object Demo06 {
  def main(args: Array[String]): Unit = {
    val res=for(i <- 1 to 10) yield {
      if(i%2==0){
        i
      }else{
        "不是偶数"
      }
    }
    println(res)
    //Vector(不是偶数, 2, 不是偶数, 4, 不是偶数, 6, 不是偶数, 8, 不是偶数, 10)
  }
}

4.6.8 使用花括号{}代替小括号()

说明
{} () 对于 for 表达式来说都可以
for 推导式有一个不成文的约定:当 for 推导式仅包含单一表达式时使用圆括号,当其包含多个表
达式时使用大括号
当使用 {} 来换行写表达式时,分号就不用写了
案例
for(i <- 1 to 3; j = i * 2) {
println(" i= " + i + " j= " + j)
}
可以写成
for{
i <- 1 to 3
j = i * 2} {
println(" i= " + i + " j= " + j)
}

 4.6.9 注意事项和细节说明

1) scala for 循环形式和 java 是较大差异,但是基本的原理还是一样的。
2) scala for 循环的步长如何控制 ! [for(i <- Range(1,3,2)]
3) 思考题:如何使用循环守卫控制步长
object stepfor {
  def main(args: Array[String]): Unit = {
    println("---------------------------")
    for(i <- 1 to 10){
      println("i="+i)
    }

    println("=====================================")
    //控制步长为2
    //Range(1,10,2)的对应的构建方法是
    //def apply(start: Int, end: Int, step: Int): Range = new Range(start,
    for(i <- Range(1,10,2)){
      println("i="+i)
    }
  }

  //控制步长的第二种方式-for 循环守卫
  for(i <-1 to 10 if i%2==1){
    println("i="+i)
  }
}

4.6.10 for 循环练习题

//打印 1~100 之间所有是 9 的倍数的整数的个数及总和.
object ForExercise01 {
  def main(args: Array[String]): Unit = {
    var count=0
    var sum=0
    for(i <- 1 to 100 if i%9==0){
      count+=1
      sum+=i
    }
    printf("count=%d sum=%d",count,sum)
    //count=11 sum=594
  }
}

4.7 while 循环控制

4.7.1基本语法

循环变量初始化
while ( 循环条件 ) {
        循环体( 语句 )
        循环变量迭代
}

4.7.2 while 循环应用实例

object Demo01 {
  def main(args: Array[String]): Unit = {
    //输出10次hello world!
    //1. 定义循环变量
    var i = 0
    while(i<10){
      println("hello world!"+i)
      i+=1
    }
  }
}

4.7.3 注意事项和细节说明

1) 循环条件是返回一个布尔值的表达式
2) while 循环是先判断再执行语句
3) If 语句不同, While 语句本身没有值,即整个 While 语句的结果是 Unit 类型的 ()
4) 因为 while 中没有返回值 , 所以当要用该语句来计算并返回结果时 , 就不可避免的使用变量 ,而
变量需要声明在 while 循环的外部,那么就等同于循环的内部对外部的变量造成了影响,所以不推荐使用,而是推荐使用 for 循环

4.8 do..while 循环控制

4.8.1 基本语法

循环变量初始化
do{
        循环体( 语句 )
        循环变量迭代
} while( 循环条件 )

4.8.2 do...while 循环应用实例

object Demo02 {
  def main(args: Array[String]): Unit = {
    var i=0
    do{
      println("hello world "+i)
      i+=1
    }while(i<10)
  }
}

4.8.3 注意事项和细节说明

1) 循环条件是返回一个布尔值的表达式
2) do..while 循环是 先执行,再判
3) while 一样,因为 do while 中没有返回值 , 所以当要用该语句来计算并返回结果时 , 就不可避
免的使用变量 ,而变量需要声明在 do...while 循环的外部,那么就等同于循环的内部对外部的变量造成了影响,所以不推荐使用,而是推荐使用 for 循环。

4.9 多重循环控制

4.9.1 介绍

1) 将一个循环放在另一个循环体内,就形成了嵌套循环。其中, for ,while ,do while 均可以作为
外层循环和内层循环。【建议一般使用两层,最多不要超过 3 层】
2) 实质上,嵌套循环就是把内层循环当成外层循环的循环体。当只有内层循环的循环条件为 false
时,才会完全跳出内层循环,才可结束外层的当次循环,开始下一次的循环。
3) 设外层循环次数为 m 次,内层为 n 次, 则内层循环体实际上需要执行 m*n=mn 次。

4.9.2 应用实例

1.统计三个班成绩情况,每个班有 5 名同学,求出各个班的平均分和所有班级的平均分[学生的成绩从
键盘输入]。
分析思路
(1) classNum 表示 班级个数 , stuNum 表示学生个数
(2) classScore 表示各个班级总分 totalScore 表示所有班级总分
(3) score 表示各个学生成绩
(4) 使用循环的方式输入成绩

def main(args: Array[String]): Unit = {
val classNum = 3
val stuNum = 5
var score = 0.0 //分数
var classScore = 0.0 //班级的总分
var totalScore = 0.0 //所有班级总分
for (i <- 1 to classNum) {
//先将 classScore 清 0
classScore = 0.0
for (j <- 1 to stuNum) {
printf("请输入第%d 班级的第%d 个学生的成绩\n", i, j)
score = StdIn.readDouble()
classScore += score
}
//累计 totalScore
totalScore += classScore
printf("第%d 班级的平均分为%.2f\n", i, classScore / stuNum)
}
printf("所有班级的平均分为%.2f", totalScore / (stuNum * classNum))
}
}

4.10 while 循环的中断

4.10.1 基本说明

Scala 内置控制结构特地去掉了 break continue,是为了更好的适应函数化编程,推荐使用函数式的风格解决 break contine 的功能,而不是一个关键字。

4.10.2 break 的应用实例

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")

println("===========================")
    //在for循环中使用break
    breakable {
      for (i <- 1 to 10) {
        println("i="+i)
        if (i == 5) {
          break()
        }
      }
    }
    println("ok2")
  }
}

4.10.3 如何实现 continue 的效果

Scala 内置控制结构特地也去掉了 continue ,是为了更好的适应函数化编程,可以使用 if else
是 循环守卫实现 continue 的效果
object ContinueDemo {
  def main(args: Array[String]): Unit = {
    //循环守卫方式
    for(i <- 1 to 10 if(i!=2 && i!=3)){
      println("i="+i)
    }
  }

//  i=1
//  i=4
//  i=5
//  i=6
//  i=7
//  i=8
//  i=9
//  i=10
}

4.11 课后练习

//100 以内的数求和,求出当和 第一次大于 20 的当前数【for】
object ForExercise02 {
  def main(args: Array[String]): Unit = {
    var sum=0
    breakable {
      for (i <- 1 to 100) {
        sum += i
        if (sum > 20) {
          println("第一次大于 20 的当前数为:"+i)//第一次大于 20 的当前数为:6
          break()
        }
      }
    }


    println("=====================")
    //除了上面的 break 机制来中断,我们也可以使用循环守卫实现中断
    var loop=true
    var sum1=0
    for(n <- 1 to 100 if loop==true){
      sum1+=n
      if(sum1>20){
        loop=false
        println("第一次大于 20 的当前数为:"+n)//第一次大于 20 的当前数为:6
      }
    }
  }
}

五、函数式编程的基础

5.1 函数式编程内容

5.1.1函数式编程内容

5.1.2 函数式编程说明

5.2 函数式编程介绍 

5.2.1几个概念的说明

在学习 Scala 中将 方法、函数、函数式编程和面向对象 编程明确一下:
1) scala 中,方法和函数几乎可以等同 ( 比如他们的定义、使用、运行机制都一样的 ) ,只是函数
的使用方式更加的灵活多样。
2) 函数式编程是从编程方式 ( 范式 ) 的角度来谈的,可以这样理解:函数式编程把函数当做一等公
民,充分利用函数、 支持的函数的多种使用方式。
比如:
Scala 当中,函数是一等公民,像变量一样,既可以作为函数的参数使用,也可以将函数赋值给一个变量. ,函数的创建不用依赖于类或者对象,而在 Java 当中,函数的创建则要依赖于类、抽象类或者接口.
3) 面向对象编程是以对象为基础的编程方式。
4) scala 中函数式编程和面向对象编程融合在一起了 
object Method2Function {
  def main(args: Array[String]): Unit = {

    //使用方法
    //先创建对象
    val dog = new Dog
    println(dog.sum(10,20))

    //方法转成函数
    val f1 = dog.sum _
    println("f1="+f1)
    println("f1="+f1(1,2))


    //函数 求两个数的和
    val f2=(n1:Int,n2:Int)=>{
      n1+n2//函数体
    }
    println("f2="+f2)
    println("f2="+f2(5,6))

  }


}

class Dog() {
  //方法
  def sum(n1: Int, n2: Int): Int = {
    n1 + n2
  }
}

5.2.2 在学习 Scala 中将方法、函数、函数式编程和面向对象编程关系分析图

5.2.3 函数式编程的小结 

1) " 函数式编程 " 是一种 " 编程范式 " (programming paradigm)。
2) 它属于 " 结构化编程 " 的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用。
3) 函数式编程中,将函数也当做 数据类型 ,因此可以接受函数当作输入(参数)和输出(返回值)。
4) 函数式编程中,最重要的就是函数。

5.3 为什么需要函数

5.4 函数的定义

5.4.1基本语法

def 函数名 ([ 参数名 : 参数类型 ], ...)[[: 返回值类型 ] =] {
        语句...
        return 返回值
}
1) 函数声明关键字为 def (definition)
2) [ 参数名 : 参数类型 ], ... :表示函数的输入 ( 就是参数列表 ), 可以没有。 如果有,多个参数使用
逗号间隔
3) 函数中的语句:表示为了实现某一功能代码块
4) 函数可以有返回值 , 也可以没有
5)返回值形式 1: : 返回值类型 =
6)返回值形式 2: = 表示返回值类型不确定,使用类型推导完成
7)返回值形式 3: 表示没有返回值,return 不生效
8) 如果没有 return , 默认以执行到最 后一行的结果作为返回

5.4.2 快速入门

object FunDemo01 {
  def main(args: Array[String]): Unit = {
    println("res="+getRes(1,2,'='))

  }

  //定义一个函数/方法
  def getRes(n1:Int,n2:Int,oper:Char) ={
    if(oper=='+'){
      n1+n2
    }else if(oper=='-'){
      n1-n2
    }else{
      null
    }
  }

}

5.5 函数-调用机制

5.5.1函数-调用过程

为了让大家更好的理解函数调用机制 , 1 个案例,并画出示意图,这个很重要,比如 getSum
算两个数的和 , 并返回结果。

object Demo01 {
  def main(args: Array[String]): Unit = {
    test(4)
    test2(4)
  }

  def test(n:Int){
    if(n>2){
      test(n-1)
    }
    println("n="+n)//2,3,4
  }

  def test2(n:Int){
    if(n>2){
      test2(n-1)
    }else{
      println("n="+n)//2
    }
  }
}

5.5.2 函数递归调用的重要的规则和小结 

函数递归需要遵守的重要原则(总结) :
1) 程序执行一个函数时,就创建一个新的受保护的独立空间 ( 新函数栈 )
2) 函数的局部变量是独立的,不会相互影响
3) 递归必须向退出递归的条件逼近,否则就是无限递归,死龟了 :)
4) 当一个函数执行完毕,或者遇到 return ,就会返回,遵守谁调用,就将结果返回给谁

5.5.3 使用 scala 递归的应用 

object Exercise01 {
  def main(args: Array[String]): Unit = {
    /*
题 1:斐波那契数
请使用递归的方式,求出斐波那契数 1,1,2,3,5,8,13... 给你一个整数 n,求出它的斐波那契数是多少?
*/

    println("fbn的结果为:"+fbn(7))
  }

  def fbn(n:Int):Int={
    //分析
    //1. 当 n = 1 结果为 1
    //2. 当 n = 2 结果是 1
    //3. 当 n> 2 是, 结果就是 就是前面两个数的和
    if(n==1 || n==2){
      1
    }else{
      fbn(n-1)+fbn(n-2)
    }

  }
}
object Exercise02 {
  def main(args: Array[String]): Unit = {
    /*题 2:求函数值
    已知 f(1)=3; f(n) = 2*f(n-1)+1;
    请使用递归的思想编程,求出 f(n)的值?*/
    println("函数f的值为:"+f(2)) //7
  }

  def f(n: Int): Int = {
    if (n == 1) {
      3
    }else{
      2 * f(n - 1) + 1
    }
  }
}
object Exercise03 {
  def main(args: Array[String]): Unit = {
    /*
    猴子吃桃子问题
    有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个!以后每天猴子都吃其中的一半,然后再
    多吃一个。当到第十天时,想再吃时(还没吃),发现只有 1 个桃子了。问题:最初共多少个桃子
    分析思路
    1. day = 10 桃子有 1
    2. day = 9 桃子有 (day10[1] + 1) *2
    3. day = 8 桃子有 (day9[4] + 1) * 2
*/
    println("桃子的个数是:"+peach(9))

  }

  def peach(day:Int): Int ={
    if(day==10){
      1
    }else{
      (peach(day+1)+1)*2
    }
  }
}

5.6 函数注意事项和细节讨论

1) 函数的形参列表可以是多个 , 如果函数没有形参,调用时 可以不带 ()
2) 形参列表和返回值列表的数据类型可以是值类型和引用类型
3) Scala 中的函数可以根据函数体最后一行代码自行推断函数返回值类型。那么在这种情况下,
return 关键字可以省略
4) 因为 Scala 可以自行推断,所以在省略 return 关键字的场合,返回值类型也可以省略
5) 如果 函数明确使用 return 关键字 ,那么函数返回就 不能使用自行推断了 , 这时要明确写成 :
回类型 = ,当然 如果你什么都不写,即使有 return 返回值为 () .
6) 如果函数明确声明无返回值(声明 Unit ),那么函数体中即使使用 return 关键字也不会有返回
7) 如果明确函数无返回值或不确定返回值类型,那么返回值类型可以省略 ( 或声明为 Any
8) Scala 语法中任何的语法结构都可以嵌套其他语法结构 ( 灵活 ) ,即:函数中可以再声明 / 定义函数, 类中可以再声明类 ,方法中可以再声明/ 定义方法
object Details03 {
def main(args: Array[String]): Unit = {
def f1(): Unit = { //ok private final
println("f1")
}
println("ok~~")
def sayOk(): Unit = { // private final sayOk$1 ()
println("main sayOk")
def sayOk(): Unit = { // private final sayOk$2 ()
println("sayok sayok")
}
}
}
def sayOk(): Unit ={ //成员
println("main sayOk")
}
}
9) Scala 函数的形参,在声明参数时,直接赋初始值 ( 默认值 ) ,这时调用函数时,如果没有指定实
参,则会使用默认值。如果指定了实参,则实参会覆盖默认值。
object Details04 {
def main(args: Array[String]): Unit = {
println(sayOk("mary"))
}
//name 形参的默认值 jack
def sayOk(name : String = "jack"): String = {
return name + " ok! " }
}
10) 如果函数存在多个参数,每一个参数都可以设定默认值,那么这个时候,传递的参数到底是覆
盖默认值,还是赋值给没有默认值的参数,就不确定了 ( 默认按照声明顺序 [ 从左到右 ]) 。在这种情况下, 可以采用带名参数
object DetailParameter05 {
  def main(args: Array[String]): Unit = {
    //mysqlCon()
    //mysqlCon("127.0.0.1", 7777) //从左到右覆盖
    //如果我们希望指定覆盖某个默认值,则使用带名参数即可,比如修改用户名和密码
    mysqlCon(user = "tom", pwd = "123")
    //f6("v2") // (错误)
    f6(p2="v2") // (?)
  }
  def mysqlCon(add:String = "localhost",port : Int = 3306, user: String = "root", pwd : String = "root"): Unit = {
    println("add=" + add)
    println("port=" + port)
    println("user=" + user)
    println("pwd=" + pwd)
  }
  def f6 ( p1 : String = "v1", p2 : String ) {
    println(p1 + p2);
  }
}
11) 递归函数未执行之前是无法推断出来结果类型,在使用时必须有明确的返回值类型

12) Scala 函数支持可变参数 

基本语法
// 支持 0 到多个参数
def sum(args :Int*) : Int = {
}
// 支持 1 到多个参数
def sum(n1: Int, args: Int*) : Int = {
}
注意事项
1. args 是集合 , 通过 for 循环 可以访问到各个值。
2. 案例演示: 编写一个函数 sum , 可以求出 1 到多个 int 的和
3. 可变参数需要写在形参列表的最后。
object VarParameters {
  def main(args: Array[String]): Unit = {
    println(sum(1,2,3,4,5))

  }

  def sum(n1: Int, args: Int*): Int = {
    println("args.length:" + args.length)
    var sum = n1
    for (item <- args) {
      sum += item
    }
    sum
  }
}

5.7 函数练习题

object Hello01 {
def main(args: Array[String]): Unit = {
def f1 = "venassa" //
println(f1)
}
}
题 1 //输出 venassa
def f1 = "venassa" 等价于
def f1() = {
"venassa" }

5.8 过程

5.8.1基本概念

 5.8.2 注意事项

注意事项和细节说明
1) 注意区分 : 如果函数声明时没有返回值类型,但是有 = 号,可以进行 类型推断 最后一行代码。
这时这个函数实际是有返回值的,该函数并不是过程。
2) 开发工具的自动代码补全功能,虽然会自动加上 Unit ,但是考虑到 Scala 语言的简单,灵活,
最好不加

5.9 惰性函数

5.9.1看一个应用场景

惰性计算(尽可能延迟表达式求值)是许多函数式编程语言的特性。惰性集合在需要时提供其元
素,无需预先计算它们,这带来了一些好处。首先, 您可以将耗时的计算推迟到绝对需要的时候 。其
次,您可以创造无限个集合,只要它们继续收到请求,就会继续提供元素。函数的惰性使用让您能够
得到更高效的代码。 Java 并没有为惰性提供原生支持, Scala 提供了。

5.9.2 画图说明[大数据推荐系统]

5.9.3 Java 实现懒加载的代码 

public class LazyDemo {
private String property; //属性也可能是一个数据库连接,文件等资源
public String getProperty() {
if (property == null) {//如果没有初始化过,那么进行初始化
property = initProperty();
}
return property;
}
private String initProperty() {
return "property";
}
}
//比如常用的单例模式懒汉式实现时就使用了上面类似的思路实现

5.9.4 惰性函数介绍

当函数返回值被声明为 lazy 时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行。
这种函数我们称之为惰性函数,在 Java 的某些框架代码中称之为懒加载 ( 延迟加载 )

5.9.5 案例演示

object LazyDemo01 {
  def main(args: Array[String]): Unit = {
    lazy val res=sum(10,20)
    println("==============")
    println("res="+res)//在要使用res前,才执行

  }

  //sum函数,返回和
  def sum(n1:Int,n2:Int):Int={
  println("sum()执行了。。")
    return n1+n2
  }

//  ==============
//  sum()执行了。。
//  res=30
}

5.9.6 注意事项和细节

1) lazy 不能修饰 var 类型的变量
2) 不但是 在调用函数时,加了 lazy , 会导致函数的执行被推迟, 我们在声明一个变量时,如果给
声明了 lazy , 那么变量值得分配也会推迟 。 比如 lazy val i = 10

5.10 异常

5.10.1 介绍

 5.10.2 Java 异常处理回顾

public class JavaExceptionDemo01 {
    public static void main(String[] args) {
        try {
            // 可疑代码
            int i = 0;
            int b = 10;
            int c = b / i; // 执行代码时,会抛出 ArithmeticException 异常
        } catch (ArithmeticException ex) {
            ex.printStackTrace();
        } catch (Exception e) { //java 中不可以把返回大的异常写在前,否则报错!!
            e.printStackTrace();
        } finally {
            // 最终要执行的代码
            System.out.println("java finally");
        }
        System.out.println("ok~~~继续执行...");
    }
}

5.10.3 Java 异常处理的注意点

1) java 语言按照 try catch-catch... finally 的方式来处理异常
2) 不管 有没有异常捕获,都会执行 finally , 因此通常可以在 finally 代码块 中释放资源
3) 可以有多个 catch ,分别捕获对应的异常,这时需要把范围小的异常类写在前面,把范围大的异
常类写在后面,否则编译错误。会提示 "Exception 'java.lang.xxxxxx' has already been caught"

5.10.4 Scala 异常处理举例

object ScalaExceptionDemo {
  def main(args: Array[String]): Unit = {

    try {
      val r = 10 / 0
    } catch {
      //说明
      //1. 在 scala 中只有一个 catch
      //2. 在 catch 中有多个 case, 每个 case 可以匹配一种异常 case ex: ArithmeticException
      //3. => 关键符号,表示后面是对该异常的处理代码块
      //4. finally 最终要执行的
      case ex:ArithmeticException => println("捕获了除数为零的算术异常")
      case ex:Exception => println("捕获了异常")
    }finally {
      //最终要执行的代码
      println("scala finally.....")
    }
    println("ok,继续执行~~~~~")
  }
}

5.10.5 Scala 异常处理小结

1) 我们将 可疑代码封装在 try 块中 。 在 try 块之后使用了一个 catch 处理程序来捕获异常。如果发
生任何异常, catch 处理程序将处理它, 程序将不会异常终止
2) Scala 的异常的工作机制和 Java 一样,但是 Scala 没有“ checked( 编译期 ) ”异常 ,即 Scala 没有编译异常这个概念,异常都是在运行的时候捕获处理。
3) throw 关键字,抛出一个异常对象 。所有异常都是 Throwable 的子类型。throw 表达式是有类型的,就是 Nothing ,因为 Nothing 是所有类型的子类型,所以 throw 表达式可以用在需要类型的地方
object ThrowDemo {
  def main(args: Array[String]): Unit = {
//    val res =test()
//    println(res.toString)

    //如果我们希望在test()抛出异常后,代码可以继续执行,我们需要处理
    try{
      test()
    }catch{
      case ex:Exception => println("捕获到一个异常:"+ex.getMessage)
    }finally {

    }
//    捕获到一个异常:异常出现
//    ok~~~~

    println("ok~~~~")
  }

  def test():Nothing={
    throw new Exception("异常出现")
  }

}
4) Scala 里,借用了模式匹配的思想来做异常的匹配,因此,在 catch 的代码里,是一系列 case
子句来匹配异常。 当匹配上后 => 有多条语句可以换行写,类似 java switch case x: 代码块 ..
5) 异常捕捉的机制与其他语言中一样,如果有异常发生,catch 子句是按次序捕捉的。因此,在 catch子句中, 越具体的异常越要靠前,越普遍的异常越靠后,如果把越普遍的异常写在前,把具体的异常写在后, scala 中也不会报错,但这样是非常不好的编程风格
6) finally 子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清
理工作,这点和 Java 一样。
7) Scala 提供了 throws 关键字来声明异常。可以使用方法定义声明异常。 它向调用者函数提供了
此方法可能引发此异常的信息。 它有助于调用函数处理并将该代码包含在 try-catch 块中,以避免程序异常终止。在 scala 中,可以使用 throws 注释来声明异常
object ThrowComment {
  def main(args: Array[String]): Unit = {

    f11()

  }

  @throws (classOf[NumberFormatException]) //等同于 NumberFormatException.class
  def f11()={
    "abc".toInt
  }
}

5.11 函数的课堂练习题

object Exercise01 {
  def main(args: Array[String]): Unit = {
    print("请输入金字塔的层数:")
    val num = StdIn.readInt()
    pyramid(num)

  }

  //编写一个函数
  def pyramid(num: Int): Unit = {
    for (i <- 1 to num) {
      for (j <- num - i to 0 by -1) {
        print(" ")
      }
      for (j <- 1 to 2 * i - 1) {
        print("*")
      }
      println()
    }
  }
}
object Exercise02 {
  def main(args: Array[String]): Unit = {
    print("请输入数字(1-9)之间的数:")
    val num=StdIn.readInt()
    mul(num)
  }

  def mul(num:Int): Unit ={
    for(i <- 1 to num ){
      for(j <- 1 to i){
        printf("%d*%d=%d\t",j,i,i*j)
      }
      println()
    }
  }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值