在Scala中 ,几乎所有语法结构都有值
If else
s为什么有值?
If 语句的返回类型取决于最后一条语句。
语句后面的分号不是必须的
Scala 没有三元运算符,不需要,if else替代了三元运算符
If 表达式会有一个返回值类型,如果 if 或者 else 返回的类型不一样,就
返回 Any 类型(所有类型的公共超类型)
如果缺少一个判断,什么都没有返回,但是 Scala 认为任何表达式都会
有值,对于空值,使用 Unit 类,写做()【叫做无有用占位符,相当于 java中的 void】
注 :行尾的位置不需要分号,只要能够从上下文判断出语句的终止即可。但是如果在单行中写多个语句,则需要分号分割 。在Scala 中, {}块,其结果也是一个表达式。块中最后一个表达式的值就是块的值。
While表达式
Scala 提供和 Java 一样的 while 和 do 循环,与 If 语句不同,While 语句
本身没有值,即整个 While 语句的结果是 Unit 类型的()。
while (n > 0) {
r = r * n
n -= 1
println (r)
}
do{
r = r * n
n -= 1
println (r)
} while(n > 0)
注: scala并没有提供break和contine语句来退出循环,如果退出使用
1.使用Boolean型的控制变量
2. 使用嵌套函数,从函数中return
3. 使用Break对象的break方法
import scala.util.control.Breaks._ //手动引入
object Break {
def main(args: Array[String]): Unit = {
var r = 1
var n = 10
breakable{ //传递值
while(n > 0){
r = r *n
n -= 1
println(n)
if (n == 5) break //
}
}
}
}
for表达式
Scala 也为 for 循环这一常见的控制结构提供了非常多的特性,这些 for
循环的特性被称为 for 推导式(for comprehension)或 for 表达式(for
expression)
推导式一词起源于函数式编程:
for (i <- -1 to 3; j <- 1 to 3) println(i+" "+j+" ")
像变量名 <- 集合 这样的表达式被称为生成器表达式,会基于集合生成单独的数值
保护式:也叫守卫,可以添加一个或者多个守卫,不需要continue语句
for (i <- 1 to 3;j<- 1 to 3 if i != j)println(i+" "+j)
for推导式可以引入变量
for (i <- 1 to 3; from = 4 -i)println( from +" ")
需要返回值怎么办?
使用yield关键字在for表达式中生成新的集合,for-yield表达式所生成的集合类型将根据所遍历的集合类型推导而出
val result = for( i <- 1 to 10)yield i %3
println(result)
{}和()对于 for 表达式来说都可以,for 推导式有一个不成文的约定:当
for 推导式仅包含单一表达式时使用原括号,当其包含多个表达式时使用大括号。值得注意的是,使用原括号时,早前版本的 Scala 要求表达式之间必须使用分号
函数
java中一般通过静态方法模拟
函数的定义
def 函数名(参数名 : 类型)[: 返回类型] = 函数体
def abs(x : Double) = if(x >= 0) x else -x
递归函数
def res(n:Int) : Int = if(n <= 0) 1 else n*res(n -1 )
递归函数必须有返回值,且指定函数返回值类型
函数参数默认值
参数类型后面设置默认值
def decotate(str:String,left: String ="[",right: String = "]") = left + str + right
//未设置参数,默认[]
println(decotate("hello"))
//设置参数
println(decotate("hello","<<<",">>>"))
函数的命名参数
不按照原先函数的参数顺序,指定参数顺序
println(decotate(left = "<<<",right = ">>>",str = "你好"))
变长函数
def sum(args : Int*): Int ={
var result = 0
for (arg <- args) result += arg
result
}
println(sum(1,4,5,6))
需要指定返回类型,否则结果会被舍弃
*_告诉编译器 1 to 5 当做参数序列处理 Range
println(sum(3 to 6 : _*))
head 和 tail
head是第一个元素,tail是剩下的元素的集合
def reds(qarg: Int*) : Int ={
if (qarg.length == 0) 0
else qarg.head + reds(qarg.tail : _*)
}
println(reds(4,2,4,59,76))
注:
- Scala可以通过=右边表达式,推断出函数的返回类型,如果函数体需要多个表达式,可以用代码块{}
2.可以将return当做函数版本的break语句- 递归函数一定要指定返回类型
- 变长参数通过*来指定,所有参数会转换为一个序列
- _* 告诉编译器,Range当做参数序列化处理
- Head是获取首元素,tail是获取剩下元素的序列
过程:
没有返回值的函数:返回类型是unit,没有 = 号
def box(s : String) { // Look carefully: no =
val border = " "- - " * s.length + " " --\ \n n" "
println(" "\ \n n " + border + "|" + s + "|\ \n n " + border)
}
懒值
当val被声明为lazy时,初始化将会被延迟,直到我们对此首次取值
使用事项:
- 用于初始化开销比较大的语句
- 解决循环依赖问题 A依赖B B依赖A
- 是开发懒数据结构的基础
def lazyed() {
lazy val property = init();//没有使用lazy修饰
println("after init()")
println(property)
}
异常
当碰到异常情况时,方法抛出一个异常,终止方法本身执行,异常传递给其调用者,调用者可以处理该异常,也可以升级到它的调用者,运行系统会一直这样升级异常,直到调用者处理,如果没有处理,终止程序
Scala的异常工作机制和java一样,但是Scala没有受检异常,不需要声明函数或者方法可能抛出某种异常,受检异常在编译器被检查,java必须声明方法所会抛出的异常类型
抛出异常: 用throw关键字,抛出一个异常对象,所有的异常都是Trowable的子类型,throw表达式都是有类型的,为Nothing,因为Nothing是所有类型的子类型,所以throw表达式可以用在需要类型的地方
//并不像 Java 代码那样,需要声明方法会抛出异常,这给程序员省去理论很多烦恼。方法上也不需要声明
def divide(x: Int, y: Int): Int = {
if (y == 0) throw new Exception("Divide by zero")
else x / y
}
捕捉异常
在 Scala 里,借用了模式匹配的思想来做异常的匹配,因此,在 catch 的
代码里,是一系列 case 字句。
异常捕捉的机制与其他语言中一样,如果有异常发生,catch 字句是按次
序捕捉的。因此,在 catch 字句中,越具体的异常越要靠前,越普遍的异常越靠后。 如果抛出的异常不在 catch 字句中,该异常则无法处理,会被升级到调用者处。
异常捕获通常采用模式匹配的语法:
try {
process(in)
} catch {
case ex: IOException => println(ex)
} finally {
in.close()
}
finally 字句用于执行不管是正常处理还是有异常发生时都需要执行的步
骤,一般用于对象的清理工作。
注:
- Throw的类型为Nothing,存在exception的if语句类型返回类型
异常代码练习
def root(x : Double) = if (x>0){sqrt(x)}else throw new IllegalArgumentException(" s" +
" should not be negative ")
try{
println(root(4))
println(root(-5))
}catch {
case e: Exception => println(e)
}finally {
println(" finally .... ")
}