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
}
}
5. Scala函数式编程的基础的更多相关文章
- Scala实战高手****第5课:零基础实战Scala函数式编程及Spark源码解析
Scala函数式编程 ----------------------------------------------------------------------------------------- ...
- Scala函数式编程(三) scala集合和函数
前情提要: scala函数式编程(二) scala基础语法介绍 scala函数式编程(二) scala基础语法介绍 前面已经稍微介绍了scala的常用语法以及面向对象的一些简要知识,这次是补充上一章的 ...
- Scala函数式编程(四)函数式的数据结构 上
这次来说说函数式的数据结构是什么样子的,本章会先用一个list来举例子说明,最后给出一个Tree数据结构的练习,放在公众号里面,练习里面给出了基本的结构,但代码是空缺的需要补上,此外还有预留的test ...
- Scala函数式编程(四)函数式的数据结构 下
前情提要 Scala函数式编程指南(一) 函数式思想介绍 scala函数式编程(二) scala基础语法介绍 Scala函数式编程(三) scala集合和函数 Scala函数式编程(四)函数式的数据结 ...
- Scala函数式编程(五) 函数式的错误处理
前情提要 Scala函数式编程指南(一) 函数式思想介绍 scala函数式编程(二) scala基础语法介绍 Scala函数式编程(三) scala集合和函数 Scala函数式编程(四)函数式的数据结 ...
- Scala函数式编程(六) 懒加载与Stream
前情提要 Scala函数式编程指南(一) 函数式思想介绍 scala函数式编程(二) scala基础语法介绍 Scala函数式编程(三) scala集合和函数 Scala函数式编程(四)函数式的数据结 ...
- Scala函数式编程进阶
package com.dtspark.scala.basics /** * 函数式编程进阶: * 1,函数和变量一样作为Scala语言的一等公民,函数可以直接赋值给变量: * 2, 函数更长用的方式 ...
- Scala函数式编程——近半年的痛并快乐着
从9月初啃完那本让人痛不欲生却又欲罢不能的<七周七并发模型>,我差不多销声匿迹了整整4个月.这几个月里,除了忙着讨食,便是继续啃另一本"锯著"--<Scala函数 ...
- 9、scala函数式编程-集合操作
一.集合操作1 1.Scala的集合体系结构 // Scala中的集合体系主要包括:Iterable.Seq.Set.Map.其中Iterable是所有集合trait的根trai.这个结构与Java的 ...
随机推荐
- (三)Java工程化--Git起步
GIT学习参考:https://git-scm.com/book/zh/v2 版本控制 版本控制记录了一个或若干文件的历史变化,便于今后查阅,恢复. 三类版本控制系统 本地版本控制系统 RCS : 本 ...
- python图片转为base64
# -*- coding: utf-8 -*- import base64 with open("/home/chaowei/1.png","rb") as f ...
- ES6新语法
ES6新语法概览 简介 ES6是JavaScript语言的新一代标准,加入了一些新的功能和语法,正式发布于2015年6月,亦称ES2015:该标准由ECMA(欧洲计算机制造联合会)的第39号技术专家委 ...
- Django-ORM多表操作(进阶)
一.创建模型 下面我们通过图书管理系统,来设计出每张表之间的对应关系. 通过上图关系,来定义一下我们的模型类. from django.db import models class Book(mode ...
- oracle dmp文件导出与导入
ORACLE 10g导入 ORACLE 11g 一.expdp.sh导出dmp文件export PATH=$PATH:$HOME/binexport ORACLE_BASE=/oracleexport ...
- tensorflow 传入值-【老鱼学tensorflow】
上个文章中讲述了tensorflow中如何定义变量以及如何读取变量的方式,本节主要讲述关于传入值. 变量主要用于在tensorflow系统中经常会被改变的值,而对于传入值,它只是当tensorflow ...
- oracle下查询的sql已经超出IIS响应时间
场景: 最近一直发生oracle下查询的sql已经超出IIS响应时间,但是后台DB的SQL查询还未终止,一直在查询.这对DB是造成很大的压力. 解决办法 增加OracleCommand 中的Comma ...
- java代码获取多边形的中心点
package com.skjd.util; import java.util.ArrayList; import java.util.List; /** * 坐标以及电子围栏相关的工具类 * @au ...
- 网络编程-Mysql-2、各种查询
1.先创建一个学生表 create table students ( id int auto_increment not null primary key, name varchar(20) not ...
- Linux 定时任务的配置
通常我们会需要定时启动一些shell脚本,类似Windows中的Task Scheduler, 下面是在AWS EMR Cluster 主几点上配置的步骤: 1. 先创建一个shell脚本,将需要执行 ...