Scala语言学习笔记——方法、函数及异常

时间:2024-07-28 10:36:20

1.Scala 方法及函数区别
 ① Scala 有方法与函数,二者在语义上的区别很小。Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话来说在类中定义的函数即是方法

② Scala 中的方法跟 Java 的类似,方法是组成类的一部分

③ Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象

④ Scala 中使用 val 语句可以定义函数,def 语句定义方法和函数

class Test {
def method (x: Int) = x + 3
val function = (x: Int) => x + 3
}
2.Scala 方法
① 方法的声明语法

基本语法

def 方法名 ([参数名: 参数类型], ...)[[: 返回值类型] =] {

语句...

return 返回值

}

说明:[ ] 表示可选,可以有,也可以没有,如果不写 = {},等于号和方法主体,那么该方法会被隐式声明为抽象(abstract),包含他的类型也是也是一个抽象类型

1) 方法声明关键字为def  (definition)

2) [参数名: 参数类型],... :表示函数的参数列表,可以没有。 如果有,多个参数使用逗号间隔

3) 方法中的语句:表示为了实现某一功能代码块

4) 方法可以有返回值,也可以没有

5) 返回值形式1:  : 返回值类型  =

def getRes(n1: Int, n2: Int, oper: Char): Int = {
n1 + n2
}
    6) 返回值形式2: =  表示返回值类型不确定,使用类型推导完成

def getRes(n1: Int, n2: Int, oper: Char):Int = { //方法声明处的返回值:Int
if (oper == '+') {
n1 + n2
} else if (oper == '-') {
n1 - n2
} else {
null //运行报错
}
}
    注意:因为null是AnyRef的子类,但是null不是AnyVal的子类,这儿编译不会报错,但是运行会报typeError异常,如果非要返回null,则可以将方法返回值 :Int 去掉,直接使用 = 号,Scala会自动进行返回类型推断

7) 返回值形式3:       表示没有返回值,return 不生效

def getRes(n1: Int, n2: Int, oper: Char) {
return n1 + n2 //代码运行正常,但是return不生效
}
    8) 如果没有return,默认以执行到最后一行的结果作为返回值

② 方法注意事项

1)方法的形参列表可以是多个, 如果方法没有形参,调用时可以不带()

2)形参列表和返回值列表的数据类型可以是值类型和引用类型

3)Scala中的方法可以根据方法体最后一行代码自行推断方法返回值类型。那么在这种情况下,return关键字可以省略

4)因为Scala可以自行推断,所以在省略return关键字的场合,返回值类型也可以省略

5)如果方法明确使用return关键字,那么方法返回就不能使用自行推断了,这时要明确写成 : 返回类型 =  ,当然如果你什么都不写,即使有return 返回值为()

def getSum(n1: Int, n2: Int) = { // = 号不能省略,如果省略了,就表示没有返回值,res得到的就是()
n1 + n2
}
 6)如果方法明确声明无返回值(声明Unit),那么方法体中即使使用return关键字也不会有返回值

7)如果明确方法无返回值或不确定返回值类型,那么返回值类型可以省略(或声明为Any)

8)Scala语法中任何的语法结构都可以嵌套其他语法结构(灵活),即:方法中可以再声明/定义方法,类中可以再声明类 ,方法中可以再声明/定义方法

object TestDef {
def main(args: Array[String]): Unit = {
//main函数中再声明/定义方法sayHello
def sayHello(name: String): String = {
def sayHello(name: String): String = {
name + " hello"
}
sayHello(name)
}
var r = sayHello("terry")
println("r=" + r) //r=terry hello
}
}
 9)Scala方法的形参,在声明参数时,直接赋初始值(默认值),这时调用方法时,如果没有指定实参,则会使用默认值。如果指定了实参,则实参会覆盖默认值

object Test {
def main(args: Array[String]): Unit = {
println(sayOk())
println(sayOk("Tom")) //覆盖默认值
}
def sayOk(name : String = "jack"): String = {
return name + " ok! "
}
}
10)如果方法存在多个参数,每一个参数都可以设定默认值,那么这个时候,传递的参数到底是覆盖默认值,还是赋值给没有默认值的参数,就不确定了(默认按照声明顺序[从左到右])。在这种情况下,可以采用带名参数

/**
* @author huleikai
* @create 2019-05-17 11:56
*/
object TestDefArgs {
def main(args: Array[String]): Unit = {
mysqlCon() //不传参则使用默认值
mysqlCon("127.0.0.1", 8080) //按默认参数顺序对应覆盖
mysqlCon(pwd = "123456") //使用带名参数覆盖某个默认值
}

def mysqlCon(add: String = "localhost", port: Int = 3306,
user: String = "root", pwd: String = "root"): Unit = {
println("add=" + add)
println("port=" + port)
println("user=" + user)
println("pwd=" + pwd)
}
}
 11)Scala 方法的形参默认是val的,因此不能在方法中进行修改

12)递归方法未执行之前是无法推断出来结果类型,在使用时必须有明确的返回值类型

13)Scala方法支持可变参数

def sum(args :Int*) : Int = {}
3.Scala 函数
    函数与方法大致一样,但在scala中,函数的概念更为重要与广泛,并且更为灵活。

① 定义一个函数

类似方法的定义规则:

def abs (x: Double) = if (x > 0) x else -x
  在函数不是递归函数的情况下,scala可以通过=后面的表达式推断出返回值类型。但是,一旦函数是递归的,那么你也需要显示指定返回值类型:

def res(n: Int): Int = if (n < 0) 1 else n * res(n-1)
  ② 匿名函数

Scala 中定义匿名函数的语法很简单,箭头左边是参数列表,右边是函数体。使用匿名函数后,我们的代码变得更简洁了。

下面的表达式就定义了一个接受一个Int类型输入参数的匿名函数:

val add = (x:Int,y:Int) => x+y
  上述定义的匿名函数,其实是下面这种写法的简写:

def add = new Function1[Int,Int]{
def apply(x:Int):Int = x+1;
}
 add 现在可作为一个函数,使用方式如下:

println(add(3, 4))
 我们也可以不给匿名函数设置参数,如下所示:

val emptyFunc = () => { println("Hello Scala!") }
 上面我们说过,如果一个方法无参数列表,则可以调用的时候直接写方法名即可,但是无参匿名函数调用时则必须带上()括号

println( emptyFunc() )
4.方法和函数的相互转化及使用
    因为函数本身其实就是一个继承了Trait的对象,所以将函数当做方法的参数传参自然没什么问题,相当于java中的方法的自定义Student类的对象传参一样,所以函数既可以当做方法的参数传入,也可以当做函数的参数传入

而方法本身不能直接当做参数,但可以先转化为函数再进行传参,如果在一个方法或函数的参数中传入符合参数类型条件的方法,那么Scala编译器会默认将该方法转化为函数传入

当然方法也可以使用方法名+空格+_将方法转化为函数,如下图所示:

5.Scala 的异常Exception
 ① Scala 异常处理举例

try {
val num = 10 / 0
} catch {
case ex: ArithmeticException => println("捕获了除数为零的算数异常")
case ex: Exception => println("捕获了异常")
} finally {
//最终要执行的代码
println("scala finally...")
}
② Scala自定义异常类

在Scala中,可以创建自己的异常。它也称为自定义异常。通过扩展Exception类,同时声明自定义异常类。在自定义类中创建自己的异常消息。下面我们来看一个例子:

//声明一个异常类继承Exception
class InvalidAgeException(s: String) extends Exception(s) {}

class ExceptionExample {
@throws(classOf[InvalidAgeException])
def validate(age: Int) {
if (age < 18) {
throw new InvalidAgeException("Not eligible")
} else {
println("You are eligible")
}
}
}

object Demo {
def main(args: Array[String]) {
var e = new ExceptionExample()
try {
e.validate(5)
} catch {
case e: Exception => println("Exception Occured : " + e)
}
}
}
③ Scala异常处理总结

1)Scala的异常的工作机制和Java一样,但是Scala没有 checked(编译期) 异常,即Scala没有编译异常这个概念,异常都是在运行的时候捕获处理

2)用throw关键字,抛出一个异常对象。所有异常都是Throwable的子类型。throw表达式是有类型的,就是Nothing,因为Nothing是所有类型的子类型,所以throw表达式可以用在需要类型的地方

def main(args: Array[String]): Unit = {
val res = test()
println (res.toString)
}
def test(): Nothing = {
throw new Exception("出现异常")
}
  3)在Scala里,借用了模式匹配的思想来做异常的匹配,因此,在catch的代码块中,是一系列case子句来匹配对应的异常。类似 java 的 switch case x: 代码块

4)异常捕捉的机制与其他语言中一样,如果有异常发生,catch子句是按次序捕捉的。因此,在catch子句中,越具体的异常越要靠前,越普遍的异常越靠后,如果把越普遍的异常写在前,把具体的异常写在后,在scala中也不会报错,但这样是非常不好的编程风格

5)Scala提供了throws关键字来声明异常。可以使用方法定义声明异常。 它向调用者函数提供了此方法可能引发此异常的信息。 它有助于调用函数处理并将该代码包含在try-catch块中,以避免程序异常终止。在scala中,可以使用throws注释来声明异常

def main(args: Array[String]): Unit = {
f11()
}
@throws(classOf[NumberFormatException]) //等同于NumberFormatException.class
def f11() = {"abc".toInt}
 
---------------------