1、条件表达式
1.1语法格式
if()值1 else 值2
1.2执行情况
条件为真,结果是值1;条件为假,结果是值2。如果if和else的返回结果同为某种类型,那么条件表达式结果也是那种类型,否则就是Any
类型
Scala的条件表达式有点类似于Java的条件运算符
1.3案例演示
1.3.1根据输入值的不同进行判断
当然也可以在一个表达式中进行多次判断
可以将上述条件表达式改造成嵌套的选择结构,可读性倒是提高了,但是简洁性降低了
利用选择表达式评定学生成绩等级
函数式编程语言,只有一个入口和一个出口,中间没有任何与外界交流的输入或输出语句,所以安全性非常好。
Java不是函数式语言,选择结构没有返回值,就必须根据不同情况对评语变量赋值。
1.3.2编写Scala程序,判断奇偶性
打开Scala项目ScalaDemo
,创建net.jojo.day02
包,在包里创建Example01
对象
package net.jojo.day02
import scala.io.StdIn
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 + "是奇数")
}
}
运行结果
利用if
结构具有返回值的特性,改写程序成为函数式风格
在net.jojo.day02
包,在包里创建Example02
对象
package net.jojo.day02
import scala.io.StdIn
object Example02 {
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)
}
}
运行结果
2.块表达式
2.1语法格式
{语句组}
- 块表达式为包含在符号“{}”中的语句块
2.2执行情况
需要注意的是,Scala中的返回值是最后一条语句的执行结果,而不需要像Java一样单独写return
关键字。如果表达式中没有执行结果,就返回一个Unit
对象,类似Java中的void
。
2.3案例演示
语句块最后一句的值就是整个块表达式的结果
语句块最后一句没有执行结果,那么块表达式结果就是Unit
3.for循环
3.1单重for循环
3.1.1语法格式
for (变量 <- 集合或数组 (条件)) {
语句组
}
3.1.2执行情况
表示将集合或数组中的每一个值循环赋给一个变量
3.1.3案例演示
任务1:输出1到10
两种方式实现,一种使用Range类,一种使用to运算符
Range(a, b): 从a到b,不包含b,跟Python里的range函数一样,含头不含尾
1 to 10表示将1到10的所有值组成一个集合,且包括10。若不想包括10,则可使用关键字until
用Java语言完成任务
打印字符直角三角形
利用map函数产生每行星号构成的向量,然后利用foreach函数循环输出
利用双重循环与流间变量,这个是Scala语言特有的东西
任务2、遍历字符串,输出每个字符
方法一、按索引取字符串的每个字符(传统for循环)
方法二:将字符串看作一个由多个字符组成的集合(增强for循环)
任务3、计算 1 + 2 + 3 + … + 100
注意sum
必须定义为var
型变量
利用集合的归并方法来求和最简单
任务4、输出列表内的偶数(过滤)
采用三种方法来实现
任务5、输出全部两位素数
for (n <- 10 to 100; if !(n % 2 == 0 || n % 3 == 0 || n % 5 == 0 || n % 7 == 0)) print(n.toString + " ")
(10 to 100).filter(n => !(n % 2 == 0 || n % 3 == 0 || n % 5 == 0 || n % 7 == 0))
3.2嵌套for循环
3.2.1语法格式
传统格式
for (变量1 <- 集合或数组(条件))
for (变量2 <- 集合或数组(条件)) {
语句组
}
}
特有格式
for (变量1 <- 集合或数组; 变量2 <- 集合或数组 (条件)) {
语句组
}
3.2.2案例演示
任务1、打印九九表
方法一、采用双重循环来实现
在net.jojo.day02
包里创建Example03
对象
package net.jojo.day02
object Example03 {
def main(args: Array[String]): Unit = {
for( i <- 1 to 9){
for (j <- 1 to i){
print(i.toString +"x"+j.toString +"="+ i*j + "\t")
}
println()
}
}
}
在net.jojo.day02
包里创建Example04
对象
package net.jojo.day02
object Example04 {
def main(args: Array[String]): Unit = {
for (i <- 1 to 9 ; j <-1 to i ){
print(i.toString +"x"+j.toString +"="+ i*j + "\t")
if (i == j) println()
}
}
}
方法三、采用单重循环与流间变量绑定来实现
在net.jojo.day02
包里创建Example05
对象
在for循环头里sep = if (i == j) "\n" else "\t"
就是流间变量绑定
package net.jojo.day02
object Example05 {
def main(args: Array[String]): Unit = {
for (i <- 1 to 9;j <- 1 to i ; sep = if (i == j) "\n" else "\t"){
print(i.toString +"x"+j.toString +"="+ (i*j) + sep)
}
}
}
方法四、采用单重循环、流间变量与yield来实现
for循环语句本身的返回值是Unit类型,无论在循环体中返回什么都是无效的,最终得到的都是Unit的值,但是可以在循环中的循环条件和循环体之间加上yield
关键字,那么就可以将循环体产生的返回值组成数组进行返回。
在net.jojo.day02
包里创建Example06
对象
package net.jojo.day02
object Example06 {
def main(args: Array[String]): Unit = {
val list = for (i <- 1 to 9 ;j <- 1 to i ;sep = if (i == j) "\n" else "\t")
yield i.toString + "x" + j + "=" + (i*j) + sep
list.foreach(print)
}
}
任务2、去掉对角线
一个三阶方阵,单元格的值是行号与列号的乘积,去掉对角线,输出剩余元素
1 | 2 | 3 |
2 | 4 | 6 |
3 | 6 | 9 |
2 | 3 | |
2 | 6 | |
3 | 6 |
方法一、传统双重循环
在net.jojo.day02
包里创建Example07
对象
package net.jojo.day02
object Example07 {
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()
}
}
}
方法二、特有双重循环
在net.jojo.day02
包里创建Example08
对象
package net.jojo.day02
object Example08 {
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()
}
}
}
方法三:采用两个流间变量和yield
在net.jojo.day02
包里创建Example09
对象
package net.jojo.day02
object Example09 {
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)
}
}
百钱买百鸡问题
公鸡一个五块钱,母鸡一个三块钱,小鸡三个一块钱,现在要用一百块钱买一百只鸡,问公鸡、母鸡、小鸡各多少只?
在net.jojo.day02
包里创建Example10
对象
package net.jojo.day02
object Example10 {
def main(args: Array[String]): Unit = {
for (cock <- 0 to 20 ; hen <- 0 to 33 ; chick = 100 - cock - hen)
if (cock*5 + hen*3 +chick/3.0 == 100)
println("公鸡:"+cock +"\t母鸡:"+hen+"\t小鸡:"+chick)
}
}
4.条件循环
4.1while循环
4.1.1语法格式
Scala的while循环与Java类似
while(条件) {
循环体
}
4.1.2案例演示
任务1、计算1+ 2 + 3 + … + 100
在net.jojo.day02
包里创建Example11
对象
注意:i
、sum
必须是变量
package net.jojo.day02
object Example11 {
def main(args: Array[String]): Unit = {
var sum = 0
var i = 1
while (i <= 100){
sum = sum + i
i = i + 1
}
println("1+2+3+...+100="+sum)
}
}
采用函数式风格来写代码,递归函数来实现求和,注意:此处sum
是常量
在net.jojo.day02
包里创建Example12
对象
package net.jojo.day02
object Example12 {
def mx(n: Int, sum: Int): Int = {
if ( n > 0) mx(n - 1 ,sum + n) else sum
}
def main(args: Array[String]): Unit = {
println("1+2+3+4+...+100="+ mx(100,0))
}
}
任务2、打印全部水仙花数(100-999)
在net.jojo.day02
包里创建Example13
对象
package net.jojo.day02
object Example13 {
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")
}
}
}
利用字符串来截取来处理,打印水仙花数,在net.jojo.day02
包里创建Example14
对象
字符转换成整数其实是ASCII码,
'0'
的ASCII码是48
,因此要减48才可以
Scala里字符串截取再转换成整数
字符串拆分(整数是可以转换成字符串来处理的)
在net.jojo.day02
包里创建Example15
对象
package net.jojo.day02
import scala.io.StdIn
object Example15 {
def main(args: Array[String]): Unit = {
print("strN = ")
val strN = StdIn.readLine()
for (c <- strN) print(c.toString + " ")
}
}
4.2do while循环
4.2.1语法格式
do {
循环体
} while(条件)
4.2.2案例演示
任务:计算1+ 2 + 3 + … + 100
在net.jojo.day02
包里创建Example16
对象
package net.jojo.day02
object Example16 {
def main(args: Array[String]): Unit = {
var sum = 0
var i = 1
do{
sum = sum +i
i = i + 1
}while(i<=100)
println("1+2+3+...+100=" + sum)
}
}
5.异常处理
5.1异常处理概述
Scala中继承了Java的异常机制,提供了程序中产生意外情况时处理的机制,抛出异常的过程和Java中基本一致,通过throw
关键字进行:throw XxxException()
,一旦抛出可以当场捕获处理或接着向上抛,捕获异常是通过 try-catch-finally
来实现的
5.2案例演示
任务:演示try-catch-finally
try-catch-finally
是有返回值的:如果没有异常就是try
语句的返回值,如果有异常就是catch
语句的返回值。注意不会是finally
的返回值,finally
即使有返回值,也会被抛弃,这点和Java是不同的。
在net.jojo.day02
包里创建Example17
对象
package net.jojo.day02
import java.io.IOException
object Example17 {
def main(args: Array[String]): Unit = {
var message = " "
val result = try {
mx()
"恭喜,程序执行正常"
}catch {
case e:NullPointerException => "空指针异常~"
case e: IOException => "呵呵,这是I/O异常"
case e: RuntimeException =>"哈哈,这是运行时异常"
case e: Exception =>"管他的,反正是异常"
}finally {
message = "程序到此为止"
"无论是否有异常,都会执行finally里面的语句"
}
println(result)
println(message)
}
def mx(): Unit = {
throw new RuntimeException("故意抛出一个运行时异常~")
}
}
执行程序,查看结果(此时有异常,result取的是catch里的返回值 - 哈哈,这是运行时异常~
,finally语句块执行了的,因此message可以打印出来 - 程序到此为止!
)
注释掉mx()
方法里的语句
执行程序,查看结果(此时有异常,result取的是try里的返回值 - 恭喜,程序执行正常!
)
在Scala里,finally的返回值不会覆盖try和catch的返回值,这一点跟Java不同。
运行程序,查看结果(此时运行test()方法,调用mx()方法抛出异常,执行catch语句块,返回异常~
,但是要被finally语句块的返回值停止!
覆盖,因此最终输出的就是停止!
)
我们把mx()
方法里的抛出异常的语句注释掉,此时程序正常运行,但是test()方法的返回值不会是恭喜,程序运行正常~
,还是会被finally语句块的返回值覆盖,成为无论如何,程序结束~
6.match结构
6.1语法格式
变量 match {
case 值1 => 表达式1或语句1
case 值2 => 表达式2或语句2
case 值3 => 表达式3或语句3
……
case _ => 表达式n或语句n
}
Scala中的match(匹配)
类似于其他语言的switch(开关)
。与Java不同的是,match语句可以应用在任何类型量或表达式上,另外不
需要调用break
语句,match默认执行完一个case后直接跳出match结构。注意,match是具有返回值的,就是被选到的case的值
6.2案例演示
任务:给城市下评语
在net.jojo.day02
包里创建Example18
对象
package net.jojo.day02
import scala.io.StdIn
object Example18 {
def main(args: Array[String]): Unit = {
print("输入城市: ")
val city = StdIn.readLine()
val comment = city match {
case "北京" => "是伟大的首都"
case "上海" => "是神奇的魔都"
case "广州" => "是迷人的妖都"
case "东京" => "是中国不可分割的一部分"
case _ => "是普通城市"
}
println(city +comment)
}
}
运行程序,查看结果
7.变量作用域
7.1Java变量作用域
Java中根据不同大括号区分变量作用范围,不允许有叠加,外部看不到内部,内部能看到外部。
7.1.1内部能访问外部
代码块里能访问代码块之前定义的变量
代码块里不能访问代码块之后定义的变量
7.2 Scala变量作用域
Scala中根据不同大括号区分变量作用范围,不允许有叠加,外部看不到内部,内部看不到外部。
7.2.1内部不能访问外部
在net.jojo.day02
包里创建Example19
对象
package net.jojo.day02
/**
* 功能:变量作用域 - 内部能访问外部
* 时间:2023年03月00号
*/
object Example19 {
def main(args: Array[String]): Unit = {
val message = "欢迎访问中国领土"
if (true){
println(message)
}
}
}
运行程序,查看结果
7.2.2外部不能访问内部
在net.jojo.day02
包里创建Example20
对象
这个情形有点类似于豪车,外面的人不能透过车窗看见里面在干嘛,但是车里的人却可以清楚地看见外面的人在干嘛。
8.补充案例
任务:评定成绩等级
8.1 编写符合函数式编程风格的Sala程序
在net.jojo.day02
包里创建Example21
对象
package net.jojo.day02
import scala.io.StdIn
/**
* 功能:成绩等级评定(采用函数式风格)
* 日期:2023年03月01日
*/
object Example21 {
def main(args: Array[String]): Unit = {
print("score = ")
val score = StdIn.readLine().toInt
val comment = if (score > 100) {
"超出范围"
} else if (score >= 90) {
"优秀"
} else if (score >= 80) {
"良好"
} else if (score >= 70) {
"中等"
} else if (score >= 60) {
"及格"
} else if (score >= 0) {
"不及格"
} else {
"超出范围"
}
println("评语:" + comment)
}
}
运行程序,查看结果
8.2函数式风格的程序有几个特点
if结构像函数一样有返回值
if结构里除了传入参数score之外,没有别的变量。
-if结构里没有与外界交流,比如输入或输出或网络连接或读取文件之类。
函数式编程是为了处理计算,不考虑系统的读写(I/O)。
函数式编程强调没有副作用(指的是函数内部与外部互动,产生运算以外的其它结果)。函数要求独立,只返回一个值,没有其它行为,尤其不能修改外部变量的值。
8.3非函数式风格的程序
看看下面这个程序 - Example22
package net.jojo.day02
import scala.io.StdIn
/**
* 功能:成绩等级评定(采用非函数式风格)
* 日期:2023年03月01日
*/
object Example22 {
def main(args: Array[String]): Unit = {
print("score = ")
val score = StdIn.readLine().toInt
var comment = ""
if (score > 100) {
comment = "超出范围"
} else if (score >= 90) {
comment = "优秀"
} else if (score >= 80) {
comment = "良好"
} else if (score >= 70) {
comment = "中等"
} else if (score >= 60) {
comment = "及格"
} else if (score >= 0) {
comment = "不及格"
} else {
comment = "超出范围"
}
println("评语:" + comment)
}
}
虽然处理结果跟上面那个程序一样,但是并不符合函数式编程风格。因为if结构有副作用,修改了if结构之外的变量comment的值
再看看下面这个程序 - Example23
package net.jojo.day02
import scala.io.StdIn
/**
* 功能:成绩等级评定(采用非函数式风格)
* 日期:2023年03月01日
*/
object Example23 {
def main(args: Array[String]): Unit = {
print("score = ")
val score = StdIn.readLine().toInt
if (score > 100) {
println("评语:超出范围")
} else if (score >= 90) {
println("评语:优秀")
} else if (score >= 80) {
println("评语:良好")
} else if (score >= 70) {
println("评语:中等")
} else if (score >= 60) {
println("评语:及格")
} else if (score >= 0) {
println("评语:不及格")
} else {
println("评语:超出范围")
}
}
}
- 不符合函数式编程风格。因为if结构有副作用,有写操作。