第五章 函数式编程基础
在Scala中,「方法」和「函数」几乎可以等同(比如他们的定义、使用、运行机制都是一样的)只是函数的使用方式更加的灵活多样。
函数实现是从编程方式的角度来谈的:函数式编程把函数当做一等公民,充分利用函数,支持函数的多种使用方式,既可以作为函数的参数使用,也可以将函数赋值给一个变量,函数的创建不用依赖于类或者对象,而在Java当中,函数的创建则要依赖于类、抽象类或者接口了。

5.1 基本语法
def 函数名(参数名:参数类型, ...):返回值类型 = {
语句...
return 返回值
}
说明:
函数声明关键字为def
参数名:参数类型,... 表示函数的输入(就是参数列表),可以没有。如果有,多个参数使用都好间隔
函数中的语句:表示为了实现某一功能代码块
函数可以有返回值,也可以没有
返回值形式1;返回值类型 = 返回值形式2:=表示返回值类型不确定,使用类型推导完成。 返回值形式3 表示没有返回值,return不生效。 如果没有热图让你,默认以执行到最后一行的结果作为返回值。
例如,使用返回值形式2展示:
object TestScala {
def main(args: Array[String]): Unit = {
val result = getRes(2,3,'+')
print(result)
}
//定义函数/方法
def getRes(num1:Int,num2:Int,oper:Char)={
if(oper == '-') num1-num2
else if(oper == '+') num1+num2
else null
}
}
结果
5
5.2 函数方法的调用机制

5.3 函数递归调用
函数递归调用的重要原则
执行一个函数时,就会创建一个新的受保护的独立空间(新函数栈) 函数的局部变量是独立的,不会相互影响。 递归必须向退出递归的条件逼近,否则就是无限递归了。 当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁。
5.4 函数调用的注意事项
函数的形参列表可以是多个,如果函数没有形参,在调用的时候可以不带(). 形参列表和返回值列表的数据类型可以是值类型和引用类型。 scala中的函数可以根据函数体最后一行代码自行推断返回值类型。那么在这种情况下,return关键字可以省略。 因为scala可以自行推断,所以在省略retrun关键字的场合,返回值类型也可以省略。 如果函数明确使用return关键字,那么函数返回就不能使用自行推断了,这时要明确写成:「返回类型」 = 如果函数声明无返回值(声明Unit),那么函数体即使使用return关键字也不会有返回值。 如果明确函数无返回值或不确定返回值类型,那么返回值类型可以省略(或声明为Any) 「scala语法中任何的语法结构都可以嵌套其他的语法结构,即:函数中可以再声明定义函数,类中可以再声明类,方法中可以再声明定义方法」。 Scala函数的形参,在声明参数时,直接赋初始值,这时调用函数时,如果没有指定实参,则会使用默认值。如果指定了实参,则实参会覆盖默认值。 scala函数的「形参默认值是val的」,因此不能在函数中进行修改。 递归函数未执行之前是无法推断出结果类型,在使用时必须要有明确的返回值类型。 scala函数支持可变参数
//支持0到多个参数
def sum(args:Int*):Int = {
}
//支持1到多个参数
def sum(n1:Int,args:Int*):Int = {
}
5.5 函数过程
将函数的返回值为unit的函数称之为过程(procedure),如果明确函数没有返回值,那么等号可以省略。
def f10(name:String):Unit = {
println(name+"hello")
}
5.6 惰性函数
惰性计算(「尽可能延迟表达式求值」)是许多函数式编程语言的特性。惰性集合在需要时提供元素,无需预先计算它们。首先,「可以将耗时的计算推迟到绝对需要的时候」。其次,「可以创造无限个集合」,只要他们继续受到请求,就会继续提供元素。函数的惰性使用能够得到更高效的代码。java并没有为惰性提供原生支持,scala提供了。
5.6.1 惰性函数介绍
当函数返回值被声明为lazy时,函数的执行将被推迟,直到首次对此取值,该函数才会执行。这种函数我们称之为惰性函数,在java的某些框架中称之为懒加载。
看下面两个例子:
非懒加载
object LazyDemo {
def main(args: Array[String]): Unit = {
val result = getSum(3, 6)
//lazy val result = getSum(3, 6)
println("******************************")
}
//定义函数/方法
def getSum(num1: Int, num2: Int) = {
println("sum被执行了...")
num1 + num2
}
}
结果
sum被执行了...
******************************
懒加载
object LazyDemo {
def main(args: Array[String]): Unit = {
//val result = getSum(3, 6)
lazy val result = getSum(3, 6)
println("******************************")
println("result = " + result)
}
//定义函数/方法
def getSum(num1: Int, num2: Int) = {
println("sum被执行了...")
num1 + num2
}
}
结果
******************************
sum被执行了...
result = 9
注意事项:
lazy不能修饰var类型的变量
不但是在调用函数时,加了lazy会导致函数的执行被推迟,我们在声明一个变量时,如果给声明了lazy,那么变量值的分配也会推迟。比如 lazy val i = 10
5.7 异常处理
scala提供try和catch块来处理异常。try块用于包含可能出错的代码。catch块用于处理try块中发生的异常。可以根据需要在程序中有任意数量的try...catch块。
语法处理上和Java类似,但是又不尽相同。
scala异常捕获案例
object MyException {
def main(args: Array[String]): Unit = {
try {
var r = 10/0
}catch {
case ex:ArithmeticException => println("捕获了除数为0的算术异常")
case ex:Exception =>println("捕获了其他异常")
}finally {
println("scala finally...")
}
}
}
结果
捕获了除数为0的算术异常
scala finally...
说明:
在scala中只有一个catch 在catch中有多个case,每个case可以匹配一种异常case ex:ArithmeticException =>关键字符号,表示后面是对该异常的处理代码块 finally最终要执行的
「对于throw关键字的说明」:
用throw关键字,抛出一个异常对象。所有异常都是Throwable的子类型。throw表达式是有类型的,就是Nothing,因为nothing
是所有类型的子类型,所以throw表达式可以用在需要类型的地方。
往期回顾
欢迎大家关注微信公众号:哦呦明知山有虎





