scala语言----函数式编程(基础篇)
1. 概念说明
方法、函数、函数式编程、面向对象编程
1)scala中,方法和函数几乎可以等同(定义、使用、运行机制一样),只是函数的使用方式更加灵活。
object Method2Function {
def main(args:Array[String]): Unit ={
val dog = new Dog
println(dog.sum(10,20))
//方法转函数
val f1 = dog.sum _ // 格式:方法名 空格 下划线
println("f1 = " + f1) // f1 = <function2> 2表示两个形参
println("f1 = " + f1(20,30))
//函数
val f2 = (a:Int,b:Int) => a + b
//val f2 = (a:Int,b:Int) => { a + b } 函数体
println("f2 = " + f2(2,3))
}
}
class Dog{
def sum(a:Int,b:Int): Int ={
a + b
}
}
2)在scala中,函数可以像变量一样,既可以作为函数的参数使用,也可以将函数赋值给一个变量,函数的创建无需依赖于类或者对象,而在java中,函数的创建要依赖于类、抽象类或接口。
3)面向对象编程是以对象为基础的编程方式。
2. 函数的定义
def 函数名 ([参数名:参数类型],...)[[:返回值类型] = ] {
语句
return 返回值
}
1)[参数名:参数类型],... :表示函数的输入(参数列表),可以没有。若有,多个参数使用逗号隔开。
2)函数可以有返回值,也可以没有。
3)返回值形式1: :返回值类型 =
4)返回值形式2:= 表示返回值类型不确定,使用类型推导完成
5)返回值形式3: 表示没有返回值,return不生效
6)若没有return,默认以执行到最后一行的结果作为返回值。
object FunctionDemo_01 {
def main(args:Array[String]): Unit ={
println(getRes(10,20,'-'))
}
def getRes(a:Int,b:Int,oper:Char) = {//无返回值类型
if(oper == '+'){
a + b
}else if(oper == '-'){
a - b
}else{
null
}
}
}
3. 函数注意事项
1)函数的形参列表可以是多个,若无形参,调用时可以不写()
object TestDemo{
def main(args:Array[String]):Unit = {
def f1 = "Hello, world!"
println(f1)
}
}
def f1 = "Hello, world!" 等价于 def f1() = {"Hello, world!"}
2)形参列表和返回值列表的数据类型可以是值类型和引用类型
3)scala函数的形参默认是val的,因此不能在函数中进行修改
def f6(p1:String = "v1",p2:String){
println(p1+p2)
}
f6("v2")//报错
f6(p2="v2")//指定覆盖某个默认值
4)递归函数未执行之前无法推断出结果类型,在使用时必须有明确的返回值类型。
5)scala支持可变参数,可变参数需要写在形参列表的最后
//支持0到多个参数
def sum(args:Int*):Int = {} //args是一个集合,通过for循环可以访问到各个值
def sum(n1:Int,args:Int*) = {}
object FunctionDemo_01 {
def main(args:Array[String]): Unit ={
println(sum(10,20,30,40))
}
def sum(n1:Int,args:Int*) :Int = {
println("args.length"+ args.length)
var s:Int = n1
for(i <- args)//通过for遍历可变参数
{
s += i
}
s
}
4. 过程
将函数的返回类型为Unit的函数称之为过程,如果明确函数没有返回值,等号可以省略。
5. 惰性函数
惰性计算(尽可能延迟表达式求值)是许多函数式编程语言的特点。惰性集合在需要时提供其元素,无需预先计算他们,这带来了好处。首先,可以将耗时的计算推迟到绝对需要的时候。其次,可以创造无限个集合,只要他们继续收到请求,就会继续提供元素。
当函数返回值被声明为lazy时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行。这种函数我们称之为惰性函数。在java的某些框架代码中称之为懒加载(延迟加载)。
object FunctionDemo_01 {
def main(args:Array[String]):Unit = {
lazy val res = sum(10,20)
println("............")
println("res = " + res)
}
def sum(n1:Int,n2:Int): Int ={
println("sum()执行了........")
return n1+n2
}
}
结果:
............
sum()执行了........
res = 30
注意:1)lazy不能修饰var类型的变量。2)在声明变量时,加了lazy,变量值的分配也会推迟。lazy val i:Int = 10
6. 异常
scala提供try和catch块来处理异常。try块用于包含可能出错的代码,catch块用于处理try块中发生的异常。
Java异常:1)java语言按照try--catch--catch...--finally的方式来处理异常。2)不管有没有异常捕获,都会执行finally,因此通常在finally代码块中释放资源。在catch块捕获异常时,范围小的异常类放在范围大的异常类前面。
try{
int i = 0;
int b = 10;
int c = b / i;//除零异常
}catch(Exception e){
e.printStackTrace();
}finally{
System.out.println("java finally");
}
System.out.println("ok------继续执行-----");
scala异常:1)scala中只有一个catch。2)在catch中有多个case,每个case可以匹配一种异常 case ex:ArithmeticException 3)=> 关键符号,表示后面是对该异常的处理代码块。4)finally 最终要执行的
try{
val r = 10 / 0
}catch{
case ex:ArithmeticException => {println("捕获除数为零的算数异常")}
case ex:Exception => println("捕获了异常")
}finally{
println("scala finally...")
}
System.out.println("ok------继续执行-----")
scala异常处理小结:
1)处理了异常,程序就不会异常终止。
2)scala的异常的工作机制和Java一样,但scala没有编译异常这个概念,异常都是在运行时捕获处理
3)用throw关键字,抛出一个异常对象。所有异常都是Throwable的子类型。throw表达式是有类型的,就是Nothing,因为Nothing是所有类型的子类型,所以throw表达式可以用在需要类型的地方。
def main(args:Array[String]){
val res = test()
println(res.toString)
}
def test():Nothing = {
throw new Exception("Wrong")
}
4)在scala中,借助了模式匹配的思想来做异常的匹配
5)若有异常发生,catch子句是按照次序捕获的。因此在catch子句中,越具体的异常要越靠前。把范围大的异常写在前,scala也不会报错。
6)scala可以使用throws注释来声明异常
object ThrowsComment{
def main(args:Array[String]): Unit ={
f11()
}
//等同于java NumberFormatException.class
def f11() = {
"abc".toInt
}
}
val n = StdIn.readInt() //控制台输入