03_Scala 函数_过程_异常

举报
alexsully 发表于 2021/05/03 20:10:04 2021/05/03
【摘要】 函数 函数, 递归函数调用机制 函数细节 过程procedure(unit的函数) 惰性函数 lazy 异常

函数 为完成某一功能的程序指令(语句)的集合

在scala中,方法和函数几乎等同(比如定义、使用、运行机制都一样的)
支持的函数的多种使用方式。如:像变量一样,既可以作为函数的参数使用,也可以将函数赋值给一个变量.
函数的创建不用依赖于类或者对象,(Java当中,函数的创建则要依赖于类、抽象类或者接口)


基本语法
def 函数名 ([参数名: 参数类型], ...)[[: 返回值类型] =] {
    语句...
    return 返回值
}

函数声明关键字为def  (definition)
[参数名: 参数类型], ...:表示参数列表, 可以没有。 如有,多个参数使用逗号间隔
函数中语句:表示为了实现某一功能代码块
函数可以有/没有返回值,如无return,默认最后一行结果为返回值

返回值形式1:    : 返回值类型  =   
返回值形式2:    =  表示返回值类型不确定,使用类型推断完成
返回值形式3:      表示没有返回值(return 不生效)

object FundemoTest1 {
  def main(args: Array[String]): Unit = {
    val n1 = 10; val n2 = 20
    println("res=" + getRes(1, 2, ')'))

    val res = sum(n1, n2)
    println("res=" + res)
  }

  def sum(n1: Int, n2: Int): Int = {
    return n1 + n2
  }

  //定义函数/方法
  def getRes(n1: Int, n2: Int, oper: Char) = {
    if (oper == '+') {
      n1 + n2 //返回
    } else if (oper == '-') {
      n1 - n2
    } else {
      //返回null
      null
    }
  }

函数-调用机制  不同的栈,指针上下移动,先进后出
函数-递归调用 函数在函数体内又调用了本身
递归重要原则:

1 程序执行一个函数时,就创建一个新的受保护的独立空间(新函数栈)
2 函数的局部变量是独立的,不会相互影响
3 递归必须向退出递归的条件逼近,否则就是无限递归,有个判断(if) 
4 当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁

函数Details

1 函数的形参列表可以是多个, 如果函数没有形参,调用时 可以不带() 
2 形参列表和返回值列表的数据类型可以是值类型和引用类型
3 函数可以根据函数体最后一行代码自行推断函数返回值类型,return关键字可以省略
4 Scala可以自行推断,在省略return关键字的场合,返回值类型也可以省略
5 如函数使用return关键字,函数返回就不能使用自行推断,明确写成 : 返回类型 =  ,
  如什么都不写,即使有return 返回值也为() 
6 如函数明确声明无返回值(声明Unit),那么函数体中即使使用return关键字 也无返回值

7 如函数无返回值或不确定返回值类型,返回值类型可省略(类型推断)(或声明为Any)
8 函数中可以再声明/定义函数,类中可以再声明类 ,方法中可以再声明/定义方法 (final 私有不能改写+继承)
9 函数的形参,在声明时如直接赋初始值(默认值),调用时,如没指定实参,则会使用默认值。如指定了实参,则会覆盖默认值

10 如函数存在多个参数,每个参数都可设定默认值,传递的参数到底是覆盖默认值,还是赋值给没有默认值的参数,就无法确定
(默认按照声明顺序[从左到右])。在这种情况下,可以采用带名参数 

11 函数的形参默认是val的,因此不能在函数中进行修改
12 递归函数未执行之前是无法推断出来结果类型,在使用时必须有明确的返回值类型
13 函数支持可变参数 (args :Int*) (可变参数需要写在形参列表的最后)

object FunDetailsTest1 {
  def main(args: Array[String]): Unit = {

    val d1 = new Dog
    val d2 = dogTest1(100, d1)
    println(d1.hashCode() == d2.hashCode())   //true

    //10 多个参数,(默认按照声明顺序[从左到右])。在这种情况下,可以采用带名参数
    mysqlCon(user = "alex", pwd = "123")



  }
  // 2 参列表和返回值列表的数据类型可以是值类型和引用类型 传入 dog 对象,返回dog 对象
  def dogTest1(n1: Int, dd: Dog) :Dog ={
    dd.name = "Robin"
    dd
  }

  // 3 函数可以根据函数体最后一行代码自行推断函数返回值类型,return关键字可以省略
  // 4 Scala可以自行推断,在省略return关键字的场合,返回值类型也可以省略
  def getSum (n1: Int , n2: Int ) = {
    n1 + n2
  }

  //5 如函数使用return关键字,函数返回就不能使用自行推断,明确写成 : 返回类型 =  ,
  //  如什么都不写,即使有return 返回值也为()
//如果写了return ,返回值类型就不能省略
  def getSum2(n1: Int , n2: Int):Int ={
    return  n1 + n2
  }

  // 如果返回值这里什么什么都没有写,即表示该函数没有返回值  return无效
  def getSum3(n1: Int , n2: Int) {
    return  n1 + n2
  }

//  6 如函数明确声明无返回值(声明Unit),那么函数体中即使使用return关键字 也无返回值
  //如果函数明确声明无返回值(声明Unit),那么函数体中即使使用return关键字也不会有返回值
  def getSum4(n1: Int , n2: Int) : Unit ={
    return  n1 + n2
  }

  // 7 如函数无返回值或不确定返回值类型,返回值类型可省略(类型推断)(或声明为Any)

  def getSum5 (n1: Int, n2:Int) ={   // : Any 也ok
    if (n1 >0 && n2 > 10)
      n1 + n2
    else  n1 - n2
  }


  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)
  }

  //12 递归函数未执行之前是无法推断出来结果类型,在使用时必须有明确的返回值类型
  def f1(n:Int): Int = {
    if (n==1) 1
    else
      f1(n-1)
  }
  //13 函数支持可变参数 (args :Int*) (可变参数需要写在形参列表的最后 )
  def getSum6 (i: Int , args: Int*):Int ={
    var sum = i
    for (item <- args){
      sum += i
    }
    sum
  }

}


class Dog {
  var name: String = "Bob"
}


过程
将函数的返回类型为Unit的函数称之为过程(procedure),如果明确函数没有返回值,那么等号可以省略
如函数声明时没有返回值类型,但是有 = 号,可以进行类型推断最后一行代码  这时函数实际是有返回值的,该函数并不是过程
开发工具的自动代码补全,会自动加上Unit,建议不加

  def helloName(name: String):Unit = {
    println("hello" + name)
    // def a
    // def b 
    //  一些列方法/函数 进行操作,但无返回值
  }



惰性函数
当函数返回值/变量 被声明为lazy时,函数的执行将被推迟,直到我们调用,该函数/变量才会执行。
这种函数我们称之为惰性函数,在Java的某些框架代码中称之为懒加载 (单例模式懒汉式)
Details: 
1 lazy 不能修饰 var 类型的变量
2 变量声明为lazy 时, 变量分配也会被推迟

object lazyTest1 {
  def main(args: Array[String]): Unit = {
    lazy val result = sum(10, 20)   // lazy 修饰, 10,20 被赋值但sum并未调用
    println("-----------------")
    println("res=" + result) //在要使用result 前才调用sum 函数
  }

  //sum函数,返回和
  def sum(n1: Int, n2: Int): Int = {
    println("sum() 刚刚被执行了..") //说明刚刚被调用
    return n1 + n2
  }}


Scala异常 
try块用于包含可能出错的代码。catch块用于处理try块中发生的异常。

Java异常
1 java语言按照try—catch-catch...—finally的方式来处理异常; finally 都会执行( 通常在finally代码块中释放资源) 
2 多个catch,把范围小的异常类写在前面,把范围大的异常类写在后面,否则编译错误。 "Exception 'java.lang.xxxxxx' has already been caught"类写在前面,把范围大的异常类写在后面,否则编译错误。 "Exception 'java.lang.xxxxxx' has already been caught"

Scala异常 details

1 将可疑代码封装在try块中, 使用一个catch处理程序来捕获异常 
2 Scala没有“checked(编译期)”异常,异常都是在运行的时候捕获处理
3 用throw关键字,抛出一个异常对象。异常都是Throwable的子类型, throw表达式的类型是Nothing(Nothing是所有类型的子类型)
4 用模式匹配的思想来做异常的匹配,在catch的代码里,多个case子句来匹配异常,当匹配上后 => 有多条语句可以换行写 
5 如果有异常发生,catch子句是按次序捕捉的,越具体的(小)异常越要靠前,越普遍的(大)异常越靠后
6 finally子句都会执行
7 Scala提供了throws关键字来声明异常 可以使用方法定义声明异常。
它向调用者函数提供了此方法可能引发此异常的信息。
它有助于调用函数处理并将该代码包含在try-catch块中,以避免程序异常终止。
在scala中,可以使用throws注释来声明异常

object exceptionTest {
  def main(args: Array[String]): Unit = {
    //1. 在scala中只有一个catch
    //2. 在catch中有多个case, 每个case可以匹配一种异常 case ex: ArithmeticException
    //3. => 关键符号,表示后面是对该异常的处理代码块
    //4. finally 最终要执行的
    try{
      test()
    }catch {
      case  ex: ArithmeticException => println("算术异常")
      case  ex: Exception => println("异常: "  + ex.getMessage)
    }finally {
      println("关闭连接")
    }

    println("如果不被try catch 捕获,该句不会输出")

  }


  def test(): Nothing = {
    throw new ArithmeticException("算术异常")//Exception("异常NO1出现~")
  }

  @throws(classOf[NumberFormatException]) //等同于Java NumberFormatException.class
  def test1()  ={
    "abc".toInt
  }

}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。