函数的定义与调用
在Scala中定义函数时,需要定义函数的函数名、参数、函数体。
我们的第一个函数如下所示:
def sayHello(name:String, age:Int) = {
if(age > 18) {
printf("Hello %s, your age is %d, you are a adult\n", name, age)
}else {
printf("Hello %s, your age is %d, you aren't a adult\n", name, age)
}
}
Scala要求必须给出所有参数的类型,但是不一定给出函数返回值的类型,只要右侧的函数体中不包含递归的语句,Scala就可以自己根据右侧的表达式推断出返回类型。
多行语句的函数体
单行的函数:def sayHello(name: String) = print("Hello, " + name)
如果函数体中有多行代码,则可以使用代码块的方式包裹多行代码,代码块中最后一行的返回值就是整个函数的返回值。与Java中不同,不是使用return返回值的。
比如如下的函数,实现累加的功能:
def sum(num:Int):Int = {
var sum = 0
for(i <- 1 to num)
sum += i
sum
}
递归函数与返回类型
如果在函数体内递归调用函数自身,则必须手动给出函数的返回类型。
例如,实现经典的斐波那契数列
def abs(n:Int):Int = {
if(n == 1 | n== 0) {
1
}else {
abs(n - 1) + abs(n - 2)
}
}
默认参数
在Scala中,有时我们调用某些函数时,不希望给出参数的具体值,而希望使用参数自身默认的值,此时就定义在定义函数时使用默认参数
def sayHello(firstName:String, middleName:String = "middle", lastName:String = "last") ={
"hello " + firstName + " " + middleName + " " + lastName
}
如果给出的参数不够,则会从左往右依次应用参数
Java与Scala实现默认参数的区别
java版
public void sayHello(int age, String name){
if(name == null) {
name = "hello";
}
if(age > 18){
System.out.println("Hello " + name +", your age is " + age + ", you are a adult");
}else {
System.out.println("Hello " + name +", your age is " + age + ", you aren't a adult");
}
}
scala版
def sayHello(age:Int, name:String = "hello") = {
if(age > 18){
printf("Hello %s, your age is %d, you are a adult\n", name, age)
}else {
printf("Hello %s, your age is %d, you aren't a adult\n", name, age)
}
}
带名参数
在调用函数时,也可以不按照函数定义的参数顺序来传递参数,而是使用带名参数的方式来传递
sayHello(firstName = "tom", lastName = "lastName", middleName = "middleName")
还可以混合使用未命名参数和带名参数,但是未命名参数必须排在带名参数前面
sayHello("tom", lastName = "lastName", middleName = "middleName")
变长参数
在Scala中,有时我们需要将函数定义为参数个数可变的形式,则此时可以使用变长参数定义函数
def sum(nums: Int*): Int = {
var sum = 0
for(num <- nums){
sum += num
}
sum
}
使用序列调用变长参数
在如果想要将一个已有的序列直接调用变长参数函数,是不对的。比如val s = sum(1 to 5)
此时需要使用Scala特殊的语法将参数定义为序列,让Scala解释器能够识别。这种语法非常有用!一定要好好主意,在spark的源码中大量地使用到了。
val s = sum(1 to 5: _*)
案例:使用递归函数实现累加
def sum(nums: Int*): Int = {
if(nums.length == 0) {
0
}
else {
nums.head + sum(nums.tail :_*)
}
}
过程
在Scala中,定义函数时,如果函数体直接包裹在了花括号里面,而没有使用=连接,则函数的返回值类型就是Unit。这样的函数就被称之为过程。过程通常用于不需要返回值的函数。
过程还有一种写法,就是将函数的返回值类型定义为Unit
def sayHello(): Unit ={
println("hello")
}
def sayHello() = println("hello")
def sayHello(){println("hello")}
lazy值
在Scala中,提供了lazy值的特性,也就是说,如果将一个变量声明为lazy,则只有在第一次使用该变量时,变量对应的表达式才会发生计算。这种特性对于特别耗时的计算操作特别有用,比如打开文件进行IO,进行网络IO等。
import scala.io.Source._
lazy val lines = fromFile("E:\\测试数据\\111.txt").mkString
即使文件不存在,也不会报错,只有第一个使用变量时会报错,证明了表达式计算的lazy特性
异常
在Scala中,异常处理和捕获机制与Java是非常相似的
try{
throw new IllegalArgumentException("x should be negative")
}catch{
case _:IllegalArgumentException => println("IllegalArgumentException")
}finally {
println("release resource")
}
try{
throw new IllegalArgumentException("user not define")
}catch{
case e1:IllegalArgumentException => println("IllegalArgumentException")
}finally {
println("release resource")
}