5. Scala函数式编程的基础

5.1 函数式编程内容及介绍顺序说明 

  5.1.1 函数式编程内容

      -函数式编程基础

        函数定义/声明

        函数运行机制

        递归(难点,[最短路径,邮差问题,迷宫问题,回溯])

        过程

        惰性函数和异常

 

      -函数式编程高级

        值函数(函数字面量)

        高阶函数

        闭包

        应用函数

        柯里化函数,抽象控制...

  5.1.2 函数式编程介绍顺序说明 

      1) 在Scala中,函数式编程和面向对象编程融合在一起,学习函数式编程需要oop的知识,同样学习oop需要函数式编程的基础

      2) 介绍顺序:函数式编程基础->面向对象编程->函数式编程

5.2函数式编程介绍 

  5.2.1 几个相关概念的说明 

      在学习Scala中将方法、函数、函数式编程和面向对象编程明确一下:

      1) 在Scala中,方法和函数几乎可以等同(比如它们的定义、使用、运行机制都是一样的),只是函数的使用方式更加的灵活多样

      2) 函数式编程是从编程方式(范式)的角度来谈的,可以这样理解:函数式编程把函数当作一等公民,充分利用函数、只是函数的多种使用方式,比如:在Scala中,函数是一等公民,像变量一样,既可以作为函数的参数使用,也可以将函数赋值给一个变量,函数的创建不用依赖于类或者对象,而在Java当中,函数的创建则要依赖于类、抽象类或者接口

      3) 面向对象编程是以对象为基础的编程方式

      4) 在Scala中函数式编程和面向对象编程融合在一起了

  5.2.2 Scala中方法、函数、函数式编程和面向对象编程关系分析图

  5.2.3 函数式编程小结 

      1) “函数式编程”是一种“编程范式”(programming paradigm)

      2) 它属于“结构化编程”的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用

      3) 函数式编程中,将函数也当做数据类型,因为也可以接受函数当作输入(参数)和输出(返回值)

      4) 函数式编程中,最重要的就是函数

5.4 函数的定义

  5.4.1 基本语法 

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

        语句...

        return 返回值

      }

      1) 函数声明关键字为def(definition)

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

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

      4) 函数可以有返回值,也可以没有

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

        返回值形式2:  = 表示返回值类型不确定,需要类型推导完成

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

      5) 如果没有return,默认以执行到最后一行的结果作为返回值

  5.4.2 快速入门案例 

object boke_demo01 {

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

  }

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

}

5.5 函数-调用机制 

  5.5.1 函数-调用过程

      为了更好的理解函数调用机制,看一个案例,比如getSum计算两个数的和,并返回结果

  5.5.2 函数递归调用的重要规则和小结 

      1) 程序执行一个函数时,就创建一个新的受保护的独立空间(新函数栈)

      2) 函数的局部变量是独立的,不会相互影响

      3) 递归必须向退出递归的条件逼近,否则就无限递归了

      4) 当一个函数执行完毕,或者遇到return,就返回,遵守谁调用,就将结果返回给谁

5.6 函数注意事项和细节讨论 

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

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

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    //形参列表和返回值列表的数据类型可以是值类型和引用类型
    val tiger = new Tiger
    val tiger2 = test01(10, tiger)
    println(tiger2.name) // jack
    println(tiger.name) // jack
    println(tiger.hashCode() + " " + tiger2.hashCode())

  }

  def test01(n1: Int, tiger: Tiger): Tiger = {
    println("n1=" + n1)
    tiger.name = "jack"
    tiger
  }
}

class Tiger {
  //一个名字属性
  var name = ""

}

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

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

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

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

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

object boke_demo01 {

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

    println(getSum2(10, 30)) // ()

    println(getSum3(9, 9)) //()

  }

  //如果写了return ,返回值类型就不能省略
  def getSum(n1: Int, n2: Int): Int = {
    return n1 + n2
  }

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

      6) 如果函数明确声明无返回值(声明Unit),那么函数体中即使使用return关键字也不会有返回值

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

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

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

object boke_demo01 {

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

    def f1(): Unit = { //ok private final
      println("f1")
    }

    println("ok~~")

    def sayOk(): Unit = { // private final sayOk$1 ()
      println("main sayOk")

      def sayOk(): Unit = { //  private final sayOk$2 ()
        println("sayok sayok")
      }
    }

  }

  def sayOk(): Unit = { //成员
    println("main sayOk")
  }
}

      9) Scala函数的形参,在声明参数时,直接赋初始值(默认值),这时调用函数时,如果没有指定实参,则会使用默认值。如果指定了实参,则实参会覆盖默认值

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    println(sayOk("mary"))
  }

  //name形参的默认值jack
  def sayOk(name: String = "jack"): String = {
    return name + " ok! "
  }
}

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

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    //    mysqlCon()
    //    mysqlCon("127.0.0.1", 7777)   //从左到右覆盖

    //如果我们希望指定覆盖某个默认值,则使用带名参数即可,比如修改用户名和密码
    mysqlCon(user = "tom", pwd = "123")

    //f6("v2")  // (错误)
    f6(p2 = "v2") // (?)

  }

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

  def f6(p1: String = "v1", p2: String) {
    println(p1 + p2);
  }

}

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

def f8(n: Int) = { //?错误,递归不能使用类型推断,必须指定返回的数据类型
    if (n < 0)
      1
    else
      n * f8(n - 1)

}

      12) Scala函数支持可变参数

      -基本语法

      //支持0到多个参数

      def sum(args : Int*) : Int = {

      }

      //支持1到多个参数

      def sum(n1 : Int, args : Int*) : Int = {

      }

      -使用注意事项

      1) args是集合,通过for循环可以访问到各个值

      2) 可变参数需要写在形参列表的最后

5.8 过程 

  5.8.1 基本概念 

      将函数的返回值类型为Unit的函数称之为过程(procedure),如果明确函数没有返回值,那么等号可以省略

  //f10没有返回值,可以使用Unit来说明
  //这时,这个函数我们也叫过程(procedure)
  def f10(name: String): Unit = {
    println(name + "hello")
  }

  5.8.2 注意事项和细节说明 

      1) 注意区分:如果函数声明时没有返回值类型,但是有等号(=),可以进行类型推断最后一行代码。这时这个函数实际是有返回值的,该函数并不是过程

      2) 开发工具的自动代码补全功能,虽然会自动加上Unit,但是考虑到Scala语言的简单,灵活,最好不加

5.9 惰性函数 

  5.9.1 看一个应用场景

      惰性计算(尽可能延迟表达式求值)是许多函数式编程语言的特性。惰性集合在需要时提供其元素。无需预先计算它们,这带来了一些好处。首先,可以将耗时的计算推迟到绝对需要的时候。其次,可以创造无限个集合,只要它们收到请求,就会继续提供元素。函数的惰性使用能够得到更高效的代码。Java并没有为惰性提供原生支持,而Scala提供了

  5.9.2 画图说明[大数据推荐系统]

  5.9.3 惰性函数介绍

      当函数返回值被声明为lazy时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行。这种函数我们称之为惰性函数

  5.9.4 案例演示

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    lazy val res = sum(10, 20)
    println("-----------------")
    println("res=" + res) //在要使用res 前,才执行
  }

  //sum函数,返回和
  def sum(n1: Int, n2: Int): Int = {
    println("sum() 执行了..") //输出一句话
    return n1 + n2
  }

}

  5.9.6 注意事项和细节 

      1) lazy不能修饰var类型的变量

      2) 不但是在调用函数时,加了lazy,会导致函数的执行被推迟,我们在声明一个变量时,如果给声明了lazy,那么变量值的分配也会推迟

5.10 异常 

  5.10.1 基本介绍 

      1) Scala提供了try和catch块来处理异常,try块用语包含可能出错的代码,catch块用于处理try块中发生的异常。可以根据需要在程序中可以有任意数量的try...catch块

      2) 语法上和Java类似,但是又不尽相同

  5.10.2 Java异常处理回顾 

public class JavaExceptionDemo01 {
    public static void main(String[] args) {

        try {
            // 可疑代码
            int i = 0;
            int b = 10;
            int c = b / i; // 执行代码时,会抛出ArithmeticException异常
        } catch (ArithmeticException ex) {
            ex.printStackTrace();
        } catch (Exception e) { //java中不可以把返回大的异常写在前,否则报错!!
            e.printStackTrace();
        } finally {
            // 最终要执行的代码
            System.out.println("java finally");
        }

        System.out.println("ok~~~继续执行...");
    }
}

  5.10.3 Java异常处理的注意点 

      1) Java语言按照try-catch-catch...-finally的方式来处理异常

      2) 不管有没有异常捕获,都会执行finally

      3) 可以有多个catch,分别捕获对应的异常,这时需要把范围小的异常类写在前面,把范围大的异常类写在后面,否则编译错误。会提示 "Exception 'java.lang.xxxxxx' has already been caught"

  5.10.4 Scala异常处理案例演示 

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

    try {
      val r = 10 / 0
    } catch {
      //说明
      //1. 在scala中只有一个catch
      //2. 在catch中有多个case, 每个case可以匹配一种异常 case ex: ArithmeticException
      //3. => 关键符号,表示后面是对该异常的处理代码块
      //4. finally 最终要执行的
      case ex: ArithmeticException => {
        println("捕获了除数为零的算数异常")
      }
      case ex: Exception => println("捕获了异常")
    } finally {
      // 最终要执行的代码
      println("scala finally...")
    }

    println("ok,继续执行~~~~~")

  }

}

  5.10.5 Scala异常处理小结 

      1) 我们将可疑代码封装在try块中,在try块之后使用了一个catch处理程序来捕获异常。如果发生任何异常,catch处理程序将处理它,程序将不会异常终止

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

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

  def test(): Nothing = {
    throw new ArithmeticException("算数异常")
  }

      4) 在Scala中,借用了模式匹配的思想来做异常的匹配,因此,在catch的代码里,是一系列的case子句来匹配异常,当匹配上后 => 有多条语句可以换行写,类似Java的 switch case x: 代码块...

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

      6) finally子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清理工作,这点和Java一样

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

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    f11()
  }

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

  

原文地址:https://www.cnblogs.com/zhanghuicheng/p/10766072.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


共收录Twitter的14款开源软件,第1页Twitter的Emoji表情 TwemojiTwemoji是Twitter开源的其完整的Emoji表情图片。开发者可以去GitHub下载完整的表情库,并把这些表情加入到自己的应用或网页中。使用示例:var i = 0;twemoji.parse(  ’emoji, m\u276
Java和Scala中关于==的区别Java:==比较两个变量本身的值,即两个对象在内存中的首地址;equals比较字符串中所包含的内容是否相同。publicstaticvoidmain(String[]args){​ Strings1="abc"; Strings2=newString("abc");​ System.out.println(s1==s2)
本篇内容主要讲解“Scala怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Scala怎么使用”吧!语法scala...
这篇文章主要介绍“Scala是一种什么语言”,在日常操作中,相信很多人在Scala是一种什么语言问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,
这篇文章主要介绍“Scala Trait怎么使用”,在日常操作中,相信很多人在Scala Trait怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,
这篇文章主要介绍“Scala类型检查与模式匹配怎么使用”,在日常操作中,相信很多人在Scala类型检查与模式匹配怎么使用问题上存在疑惑,小编查阅了各式资料,整理...
这篇文章主要介绍“scala中常用但不常见的符号有哪些”,在日常操作中,相信很多人在scala中常用但不常见的符号有哪些问题上存在疑惑,小编查阅了各式资料,整理...
本篇内容主要讲解“Scala基础知识有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Scala基础知识有哪些”...
本篇内容介绍了“scala基础知识点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧...
本篇内容介绍了“Scala下划线怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧...
本篇内容主要讲解“Scala提取器怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Scala提取器怎么使用”...
这篇文章主要讲解了“Scala基础语法有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Scala基础语法有...
本篇内容主要讲解“Scala方法与函数怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Scala方法与函数怎...
这篇文章主要讲解了“scala条件控制与循环怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“scala条...
这篇文章主要介绍“scala函数怎么定义和调用”,在日常操作中,相信很多人在scala函数怎么定义和调用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操
这篇文章主要介绍“scala如何声明变量”,在日常操作中,相信很多人在scala如何声明变量问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对...
这篇文章主要讲解了“scala的Map和Tuple怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“scala的Ma...
这篇文章主要介绍“scala的隐式参数有什么作用”,在日常操作中,相信很多人在scala的隐式参数有什么作用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的...
本篇内容主要讲解“Scala怎么进行文件写操作”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Scala怎么进行文件...
这篇文章主要讲解了“Scala怎么声明数组”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Scala怎么声明数组...