scala-04-函数式编程基础
概念及定义
在Scala当中,函数是一等公民,像变量一样,既可以作为函数的参数使用,也可以将函数赋值给一个变量. ,函数的创建不用依赖于类或者对象,而在Java当中,函数的创建则要依赖于类、抽象类或者接口
def 函数名 ([参数名: 参数类型], ...)[[: 返回值类型] =] {
语句... //完成某个功能
return 返回值
}
- 函数声明关键字为def (definition)
- [参数名: 参数类型], ...:表示函数的输入(就是参数列表), 可以没有。 如果有,多个参数使用逗号间隔
- 函数中的语句:表示为了实现某一功能代码块
- 函数可以有返回值,也可以没有
- 返回值形式1: // : 返回值类型 = 表示有返回值,并且指定了返回值的类型
- 返回值形式2: // = , 表示返回值类型,使用类型推导
- 返回值形式3: // 空的 ,表示没有返回值,即使有return 也不生效
- 如果没有return ,默认以执行到最后一行的结果作为返回值
object HelloScala {
def main(args: Array[String]): Unit = {
//使用方法
//先创建一个对象
val dog = new Dog
println(dog.sum(10, 20))
//函数, 求两个数的和
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
}
}
}
}
//1. 如果我们返回的类型是多种的,则推荐使用类型推导
def sum(n1: Int, n2: Int, oper: Char) = {
//判断
if (oper == '+') {
n1 + n2
} else if (oper == '-') {
n1 - n2
} else {
null
}
}
注意事项及细节
1.函数的形参列表可以是多个, 如果函数没有形参,调用时可以不带()
sayHello
def sayHello(): Unit = {
println("sayHello")
}
2.形参列表和返回值列表的数据类型可以是值类型和引用类型。
3.Scala中的函数可以根据函数体最后一行代码自行推断函数返回值类型。那么在这种情况下,return关键字可以省略
def sum(n1: Int, n2: Int): Int = {
// return n1 + n2
n1 + n2
}
4.因为Scala可以自行推断,所以在省略return关键字的场合,返回值类型也可以省略
def sum2(n1: Int, n2: Int) = {
// return n1 + n2
n1 + n2
}
5.如果函数明确使用return关键字,那么函数返回就不能使用自行推断了,这时要明确写成 : 返回类型 = ,当然如果你什么都不写,即使有return 返回值为()
// def sum3(n1:Int,n2:Int) = {
// return n1 + n2
// }
//如果你什么都不写,即使有return 返回值为()
def sum4(n1: Int, n2: Int) {
// return n1 + n2
return n1 + n2
}
6.如果函数明确声明无返回值(声明Unit),那么函数体中即使使用return关键字也不会有返回值
def sum5(n1: Int, n2: Int): Unit = {
// return n1 + n2
return n1 + n2
}
7.如果明确函数无返回值或不确定返回值类型,那么返回值类型可以省略(或声明为Any)
def f10(n: Int): Any = {
if (n == 1) {
10
} else {
"yes"
}
}
8.Scala语法中任何的语法结构都可以嵌套其他语法结构(灵活),即:函数/方法中可以再声明/定义函数/方法,类中可以再声明类
val f11 = (s: String) => {
println("s=" + s)
val f12 = (s: String) => {
println("f12 s=" + s)
}
f12("yes")
}
9.Scala函数的形参,在声明参数时,直接赋初始值(默认值),这时调用函数时,如果没有指定实参,则会使用默认值。如果指定了实参,则实参会覆盖默认值
def sayOK(s: String = "北京"): Unit = {
println("sayOk =" + s)
}
//9.测试
sayOK()
sayOK("深圳")
10.如果存在多个参数,每一个参数都可以设定默认值,那么这个时候,传递的参数到底是覆盖默认值,还是赋值给没有默认值的参数,就不确定了(默认按照声明顺序[从左到右])。在这种情况下,可以采用带名参数
//10测试
//mysqlCon("192.168.11.11")//错误,因为没有给port值
//使用命名参数来指定某个形参的值,这样就更灵活
mysqlCon("192,168.11.11", port = 8888)
def mysqlCon(add: String = "localhost", port: Int,
user: String = "root", pwd: String = "root"): Unit = {
println("add=" + add)
println("port=" + port)
println("user=" + user)
println("pwd=" + pwd)
}
11.scala 函数的形参默认是val的,因此不能在函数中进行修改.
12.递归函数未执行之前是无法推断出来结果类型,在使用时必须有明确的返回值类型
def f8(n: Int):Int = { //如果省略返回值类型则错误,递归不能使用类型推断,必须指定返回的数据类型
if (n <= 0)
1
else
n * f8(n - 1)
}
13.Scala函数支持可变参数,注意可变参数只能放在最后
def sum10(n:Int,args:Int*): Int = {
var res = n
for (i<-args) {
res += i
}
res
}
println(sum10(1,2,3)) //6
println(sum10(1,2,3,4,5)) // 15
过程
将函数的返回类型为Unit的函数称之为过程(procedure),如果明确函数没有返回值,那么等号可以省略
注意区分: 如果函数声明时没有返回值类型,但是有 = 号,可以进行类型推断最后一行代码。这时这个函数实际是有返回值的,该函数并不是过程。
惰性函数
当函数返回值被声明为lazy时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行。这种函数我们称之为惰性函数,在Java的某些框架代码中称之为懒加载(延迟加载)
1 lazy 不能修饰 var 类型的变量
2 不但是在调用函数时,加了 lazy ,会导致函数的执行被推迟,我们在声明一个变量时,如果给声明了 lazy ,那么变量值的分配也会推迟
object LazyDemo {
def main(args: Array[String]): Unit = {
lazy val res = sum(1,2)
println("-----------------------")
println("res=" + res) //当需要使用到res时,就会真正的开始计算
}
//将来这个计算方法是非常耗费运力
def sum(n1:Int,n2:Int): Int = {
println("sum 被调用..")
n1 + n2
}
}
异常
try {
var res = 10 / 0
} catch {
case ex: ArithmeticException => {
println("算术异常=" + ex.getMessage)
println("111")
println("222")
}
case ex: Exception => println("异常信息=" + ex.getMessage)
} finally {
println("finaly的代码...")
}
def test(): Nothing = {
throw new Exception("不对")
}