一门多范式的编程语言Scala学习的第二天-函数的使用
2.12 scala中的函数式编程
* scala中的函数式编程
*
* 面向对象编程:将对象当作参数一样传来传去
* 1、对象可以当作方法参数传递
* 2、对象也可以当作方法的返回值返回
* 当看到类,抽象类,接口的时候,今后无论是参数类型还是返回值类型,都需要提供对应的实现类对象
*
* 面向函数式编程:将函数当作参数一样传来传去
* 1、函数A当作函数B的参数进行传递
* 2、函数A当作函数B的返回值返回
*
* 在scala中,将函数也当作一个对象,对象就有类型
* 函数在scala也有类型的说法
* 参数类型=>返回值类型
object Demo10fun {
def main(args: Array[String]): Unit = {
//是一个参数是字符串类型,返回值是整数类型的函数
def fun1(a1:String):Int={
a1.toInt
}
val res1: Int = fun1("1000")
println(res1)
//定义变量的方式,定义一个函数
//将函数当作对象,赋值给类型是函数类型的变量,将来可以直接通过变量调用函数
val fun2:String=>Int=fun1
val res2: Int = fun2("2000")
println(res2)
/**
* 函数A作为函数B的参数定义
*
* 本质上是将函数A的处理逻辑主体传给了函数B,在函数B中使用这个处理逻辑
*/
//f:String=>Int 相当于函数A
//fun3相当于函数B
def fun3(f:String=>Int):Int={
val a1:Int=f("100")
a1+100
}
def show1(a1:String):Int=a1.toInt
val res4: Int = fun3(show1)
println(res4)
def show2(a1: String): Int = a1.toInt+100
val res5: Int = fun3(show2)
println(res5)
//定义一个函数fun1, 函数的参数列表中,既有正常的类型参数,也有函数类型的参数
def fun4(s:String,f:String=>Int): Int = {
val b1:Int=f(s)
b1+111
}
def show3(a1: String): Int = a1.toInt + 100
val res6: Int = fun4("1000",show3)
println(res6)
//使用lambda表达式改写函数作为参数传递的调用形式
fun4("100",(s:String)=>s.toInt)
fun4("100",(s:String)=>s.toInt+100)
//在Scala中数据类型可以自动推断
val res7: Int = fun4("1000", s => s.toInt + 100)
println(res7)
////如果当作参数的函数的参数只在函数主体使用了一次,那么可以使用_代替
fun4("100",_.toInt+100)
}
}
1、函数当作参数传递的应用
object Demo11fun {
def main(args: Array[String]): Unit = {
val arr1: Array[Int] = Array(11, 22, 33, 44, 55)
def fun1(i:Int): Unit = {
println(i*2)
}
//def foreach[U](f: A => U): Unit
//foreach函数需要一个参数和数组元素一样类型的类型,返回值是Unit的函数
//foreach函数的主要作用是将调用该方法的序列中的元素,依次取出传递给后面的函数进行处理
arr1.foreach(fun1)
// scala自带的一个函数
// def println(x: Any) = Console.println(x)
// Any可以接收任意的数据类型元素
arr1.foreach(println)
}
}
2、函数当作返回值返回
object Demo12fun {
def main(args: Array[String]): Unit = {
/**
* fun1: 参数是String类型,返回值是一个函数(参数是String类型,返回值是Int)
*/
//定义返回值是函数的函数方式1:
def fun1(s1:String):String=>Int={
def fun2(s2:String):Int={
s2.toInt+s1.toInt
}
fun2
}
//调用函数的返回值是函数的方式1
val res1: String => Int = fun1("100")
val res2: Int = res1("100")
println(res2)
//定义方式2(是方式1的简化写法):
def fun2(s1:String)(s2:String):Int={
s1.toInt+s2.toInt
}
val res3: Int = fun2("1")("100")
println(res3)
//一般这么用方式二
val resfun: String => Int = fun2("10")
val res4: Int = resfun("11")
println(res4)
val res5: Int = resfun("22")
println(res5)
val res6: Int = resfun("33")
println(res6)
//另一种写法
def fun3(s1:String,s2:String):Int={
s1.toInt+s2.toInt
}
val res7: Int = fun3("100", "10")
println(res7)
/**
* 使用下划线进行占位,那么Scala会自动根据参数类型和返回值类型,创建一个新的相符合的函数
* 偏函数
*/
val funn3: String => Int = fun3("100", _)
val res8: Int = funn3("100")
println(res8)
val res9: Int = funn3("1000")
println(res9)
}
}
2.13数组
//数组:在内存中一块连续固定大小的空间,有索引可以检索数据,查询快,但是增删速度较慢
//创建一个数组
val arr1: Array[Int] = Array(11, 22, 33, 44, 55)
println(arr1(0))
println(arr1(1))
println(arr1(2))
println(arr1(3))
println(arr1(4))
3、Scala中的”_"的用法总结
在Scala中的大部分情况下,表示所有或者默认值或者占位符的时候,都使用下划线
1、导包时
- 多引用的方法,和Java中的*类似,相当于该类下面的任意子类
import scala.collection.mutable._
2、在访问元组时
- 和值在一起使用则表示第几个元素
val/var 元组名 = (元素1, 元素2, 元素3....)
//获取第一个元素
元组名._1
//获取第二个元素
元组名._2
3、根据定义的变量的类型的初始值进行的占位符
var gender:String = _
4、使用下划线来简化函数的定义
-
当函数的参数在函数体中只出现一次,而且函数体没有嵌套调用时,可以使用下划线来简化函数的定义
def main(args: Array[String]): Unit = {
val a = List(1,2,3,4,5)
// a.foreach(x=>println(x))
a.foreach(println(_))
}
5、用于元素匹配,匹配每一个元素
List(1,2,3,4,5,6,7,8,9).filter(_ % 2 == 0)
6、用于替换函数中的参数
-
函数参数在函数中只出现一次,则可以使用下划线代替
/**
* 偏函数
*/
val f1: String => Int = function1("1", _)
val res1: Int = f1("1000")
val res2: Int = f1("2000")
val res3: Int = f1("3000")
println(s"res1:$res1,res2:$res2,res3:$res3")
7、用于模式匹配中的默认匹配项
case表达式中的无需使用到的匹配到的变量,可以用下划线代替
变量 match {
case "常量1" => 表达式1
case "常量2" => 表达式2
case "常量3" => 表达式3
case _ => 表达式4 // 默认匹配项
}
str match {
case "hadoop" => println("大数据分布式存储和计算框架")
case "zookeeper" => println("大数据分布式协调服务框架")
case "spark" => println("大数据分布式内存计算框架")
case _ => println("未匹配")
}
在case校验时,变量没有被使用,也可以用下划线替代
-
下面是Scala中处理异常的时间的使用
/**
* 也可以手动的抛出异常
*/
val sc = new Scanner(System.in)
print("输入除数:")
val cs: Int = sc.nextInt()
if(cs!=0){
println(10/cs)
}else{
throw new ArithmeticException("您输入的除数是0")
}
}catch{
//类似于sql语句中case when
case e:ArithmeticException=>
// println("除0异常")
e.printStackTrace()
case e:ArrayIndexOutOfBoundsException=>
println("数组越界异常")
case _ =>
println("出现异常")
}finally {
//今后finally中的处理大部分情况下都与释放资源有关
println("这是finally代码块")
}
8、在定义变量时
- 在定义变量时,使用下划线占位,就表示将来会赋予该变量默认值
/**
* 定义成员变量
*/
val _name: String = name
val _age: Int = age
var _gender: String = _ // 这个下划线,就表示将来会赋予默认值
4、Scala中的集合
List: 元素有序,且可以发生重复,长度是固定的
Set:元素无序,且唯一,长度固定的
Map:元素是以键值对的形式,键是唯一的
Tuple:元组,长度是固定的,每一个元素的数据类型可以是不一样的
4.1ArrayList
object Demo13ArrayList {
def main(args: Array[String]): Unit = {
val list1: util.ArrayList[Int] = new util.ArrayList[Int]
list1.add(11)
list1.add(123)
list1.add(22)
list1.add(31)
list1.add(17)
println(list1)
var i=0
while (i<list1.size()){
val res1: Int = list1.get(i)
println(res1)
i+=1
}
}
}
4.2 List
- List中的基础用法,和Java中的集合用法一致
//创建一个scala中的List集合
//创建了一个空集合
// val list1: List[Nothing] = List()
val list2: List[Int] = List(34, 11, 22, 11, 33, 44, 55, 22, 75, 987, 1, 12, 34, 66, 77)
println(list2)
//获取List集合的长度
println(list2.size)
println(list2.length)
println("=" * 50)
//可以直接通过索引下标获取元素
println(list2(0))
println(list2(1))
println(list2(2))
println("=" * 50)
//scala推荐获取第一个元素的方式是调用head函数
println(list2.head)
println(list2.last)
//根据指定的分隔符拼接元素
println(list2.mkString("|"))
println("=" * 50)
val resList1: List[Int] = list2.reverse //返回一个新的集合
println(s"list2:$list2")
println(s"resList1:$resList1")
println("=" * 50)
//对集合中元素进行去重
val resList2: List[Int] = list2.distinct //返回一个新的集合
println(s"list2:$list2")
println(s"resList2:$resList2")
println("=" * 50)
val resList3: List[Int] = list2.tail // 除去第一个,其余的元素返回一个新的集合
println(s"list2:$list2")
println(s"resList3:$resList3")
println("=" * 50)
val resList4: List[Int] = list2.take(5) // 从左向右取元素,取若干个
println(s"list2:$list2")
println(s"resList4:$resList4")
println("=" * 50)
val resList5: List[Int] = list2.takeRight(5) //取右边的几个,组成新的集合
println(s"list2:$list2")
println(s"resList5:$resList5")
println("=" * 50)
//从第一个判断取数据,直到不符合条件停止
val resList10: List[Int] = list2.takeWhile((e: Int) => e % 2 == 0)
println(s"list2:$list2")
println(s"resList10:$resList10")
println("***********************************" * 50)
val res1: Int = list2.sum // 元素必须是数值
println(s"集合中的元素和为:$res1")
println("=" * 50)
val res2: Int = list2.max
println(s"集合中的元素最大值为:$res2")
println("=" * 50)
//集合的遍历
for (e <- list2) {
println(e)
}
println("=" * 50)
- Scala中的List高阶函数用法
/**
* 高阶函数:
* foreach: 将集合中的元素依次取出传入到后面的函数中
* 注意:没有返回值的,要么就输出,要么就其他方式处理掉了
*/
//def foreach[U](f: A => U)
// list2.foreach((e: Int) => println(e))
// list2.foreach(println)
//需求1:使用foreach求出集合中偶数的和
var ouSum = 0
var jiSum = 0
list2.foreach((e: Int) => {
if (e % 2 == 0) {
ouSum += e
} else {
jiSum += e
}
})
println(s"集合中偶数之和为:$ouSum")
println(s"集合中奇数之和为:$jiSum")
println("=" * 50)
/**
* 高阶函数:
* map: 依次处理每一个元素,得到一个新的结果,返回到一个新的集合中
*/
val list3: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
//需求2:将集合中的每一个元素*2
val resList6: List[Int] = list3.map((e: Int) => e * 2)
println(s"list3:$list3")
println(s"resList6:$resList6")
/**
* 高阶函数:
* filter: 保留符合条件的元素
*/
println("=" * 50)
val list4: List[Int] = List(4, 7, 9, 10, 12, 11, 14, 9, 7)
val resList7: List[Int] = list4.filter((e: Int) => e % 2 == 0)
println(s"list4:$list4")
println(s"resList7:$resList7")
/**
* 高阶函数:
* sortBy: 排序
* sortWith: 两个数之间的关系排序
*/
println("=" * 50)
val resList8: List[Int] = list4.sortBy((e: Int) => -e)
println(s"list4:$list4")
println(s"resList8:$resList8")
val resList9: List[Int] = list4.sortWith((x: Int, y: Int) => x > y)
println(s"list4:$list4")
println(s"resList9:$resList9")
/**
* 高阶函数:
* flatMap: 扁平化
*/
println("=" * 50)
val list5: List[String] = List("hello|world|java", "hello|hadoop|flink", "scala|spark|hadoop")
val resTmp1: List[String] = list5.flatMap((e: String) => e.split("\\|"))
resTmp1.foreach(println)
/**
* 高阶函数:
* groupBy: 分组
*/
val list6: List[String] = List("hello", "world", "java", "hadoop", "flink", "java", "hadoop", "flink", "flink", "java", "hadoop", "flink", "java", "hadoop", "hello", "world", "java", "hadoop", "hello", "world", "java", "hadoop")
val map: Map[String, List[String]] = list6.groupBy((e: String) => e)
for (e <- map) {
println(e)
}
/**
* 基本函数
*
* 高阶函数:
* foreach: 依次取出元素,进行后面函数逻辑,没有返回值
* map: 依次取出元素,进行后面函数逻辑,有返回值,返回新的集合
* filter: 所有数据中取出符合条件的元素
* sortBy/sortWith: 排序
* flatMap: 扁平化
* groupBy: 分组,结果是一个map集合
*/
4.3Set
set集合: scala中的Set集合也是不可变的,除了排序相关的函数以外,List集合有的高阶函数,Set集合也有
val set1: Set[Int] = Set(1, 4, 3, 6, 5)
val set2: Set[Int] = Set(3, 6, 5, 7, 8)
println(s"$set1")
println(s"$set2")
// val res1: Set[Int] = set1.&(set2)
//求交集
val res2: Set[Int] = set1 & set2
println(s"$res2")
//求并集
val res3: Set[Int] = set1.|(set2)
println(s"$res3")
//求差集
val res4: Set[Int] = set1.&~(set2)
println(s"$res4")
/**
* list集合和set集合可以相互转换
*/
val list1: List[Int] = List(11, 22, 33, 44, 55, 11, 22, 44, 88, 33, 44, 99, 11, 22, 55)
val set3: Set[Int] = list1.toSet
println(s"$set3")
val list2: List[Int] = set3.toList.sortBy((e: Int) => e)
println(s"$list2")