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

5. Scala函数式编程的基础的更多相关文章

  1. Scala实战高手****第5课:零基础实战Scala函数式编程及Spark源码解析

    Scala函数式编程 ----------------------------------------------------------------------------------------- ...

  2. Scala函数式编程(三) scala集合和函数

    前情提要: scala函数式编程(二) scala基础语法介绍 scala函数式编程(二) scala基础语法介绍 前面已经稍微介绍了scala的常用语法以及面向对象的一些简要知识,这次是补充上一章的 ...

  3. Scala函数式编程(四)函数式的数据结构 上

    这次来说说函数式的数据结构是什么样子的,本章会先用一个list来举例子说明,最后给出一个Tree数据结构的练习,放在公众号里面,练习里面给出了基本的结构,但代码是空缺的需要补上,此外还有预留的test ...

  4. Scala函数式编程(四)函数式的数据结构 下

    前情提要 Scala函数式编程指南(一) 函数式思想介绍 scala函数式编程(二) scala基础语法介绍 Scala函数式编程(三) scala集合和函数 Scala函数式编程(四)函数式的数据结 ...

  5. Scala函数式编程(五) 函数式的错误处理

    前情提要 Scala函数式编程指南(一) 函数式思想介绍 scala函数式编程(二) scala基础语法介绍 Scala函数式编程(三) scala集合和函数 Scala函数式编程(四)函数式的数据结 ...

  6. Scala函数式编程(六) 懒加载与Stream

    前情提要 Scala函数式编程指南(一) 函数式思想介绍 scala函数式编程(二) scala基础语法介绍 Scala函数式编程(三) scala集合和函数 Scala函数式编程(四)函数式的数据结 ...

  7. Scala函数式编程进阶

    package com.dtspark.scala.basics /** * 函数式编程进阶: * 1,函数和变量一样作为Scala语言的一等公民,函数可以直接赋值给变量: * 2, 函数更长用的方式 ...

  8. Scala函数式编程——近半年的痛并快乐着

    从9月初啃完那本让人痛不欲生却又欲罢不能的<七周七并发模型>,我差不多销声匿迹了整整4个月.这几个月里,除了忙着讨食,便是继续啃另一本"锯著"--<Scala函数 ...

  9. 9、scala函数式编程-集合操作

    一.集合操作1 1.Scala的集合体系结构 // Scala中的集合体系主要包括:Iterable.Seq.Set.Map.其中Iterable是所有集合trait的根trai.这个结构与Java的 ...

随机推荐

  1. (三)Java工程化--Git起步

    GIT学习参考:https://git-scm.com/book/zh/v2 版本控制 版本控制记录了一个或若干文件的历史变化,便于今后查阅,恢复. 三类版本控制系统 本地版本控制系统 RCS : 本 ...

  2. python图片转为base64

    # -*- coding: utf-8 -*- import base64 with open("/home/chaowei/1.png","rb") as f ...

  3. ES6新语法

    ES6新语法概览 简介 ES6是JavaScript语言的新一代标准,加入了一些新的功能和语法,正式发布于2015年6月,亦称ES2015:该标准由ECMA(欧洲计算机制造联合会)的第39号技术专家委 ...

  4. Django-ORM多表操作(进阶)

    一.创建模型 下面我们通过图书管理系统,来设计出每张表之间的对应关系. 通过上图关系,来定义一下我们的模型类. from django.db import models class Book(mode ...

  5. oracle dmp文件导出与导入

    ORACLE 10g导入 ORACLE 11g 一.expdp.sh导出dmp文件export PATH=$PATH:$HOME/binexport ORACLE_BASE=/oracleexport ...

  6. tensorflow 传入值-【老鱼学tensorflow】

    上个文章中讲述了tensorflow中如何定义变量以及如何读取变量的方式,本节主要讲述关于传入值. 变量主要用于在tensorflow系统中经常会被改变的值,而对于传入值,它只是当tensorflow ...

  7. oracle下查询的sql已经超出IIS响应时间

    场景: 最近一直发生oracle下查询的sql已经超出IIS响应时间,但是后台DB的SQL查询还未终止,一直在查询.这对DB是造成很大的压力. 解决办法 增加OracleCommand 中的Comma ...

  8. java代码获取多边形的中心点

    package com.skjd.util; import java.util.ArrayList; import java.util.List; /** * 坐标以及电子围栏相关的工具类 * @au ...

  9. 网络编程-Mysql-2、各种查询

    1.先创建一个学生表 create table students ( id int auto_increment not null primary key, name varchar(20)  not ...

  10. Linux 定时任务的配置

    通常我们会需要定时启动一些shell脚本,类似Windows中的Task Scheduler, 下面是在AWS EMR Cluster 主几点上配置的步骤: 1. 先创建一个shell脚本,将需要执行 ...