初识scala(下)
面向函数编程
面向对象编程, 将一个对象传来传去,
1、以对象作为参数
2、以对象作为返回值
需要明确对象的类型
面向函数编程: 将一个函数传来传去 — 高阶函数
1、以函数作为参数
2、以函数作为返回值
需要明确函数的类型
函数的类型
1、函数的类型和函数名无关
2、函数类型油参数类型和返回值类型决定
def fun1(str: String): Int = {
str.toInt
}
println(fun1("100"))
//String => Int 由于描述函数的类型
// => 左边是函数参数的类型,=> 右边是函数返回值的类型
val f: String => Int = fun1
println(f("200"))
println(f)
高阶函数
1、以函数作为参数
2、以函数作为返回值
lambda 表达式 – 匿名函数
/*
(s: String) => s.toInt
=> 左边是参数
=> 右边是返回值
*/
fun((s: String) => {
s.toInt + 200
})
//大括号可以省略
fun((s: String) => s.toInt)
//可以自动推断参数的类型
fun(s => s.toInt)
//如果参数只使用了异常可以使用下划线代替
fun(_.toInt)
用下划线代替变量
//省略类型
array.foreach(i => print(i))
//下划线代替变量
array.foreach(println(_))
scala中的方法
* foreach: 循环遍历,没有返回值
* map: 对集合中的数据进行处理,返回一个新的集合
* filter : 对集合中的数据进行过滤
* sortBy: 指定一个字段进行排序
* flatMap : 将一行数据拆分成多行数据
* groupBy : 指定一个字段进行分组
map方法
循环数组,列表,将数组,列表中的元素一个一个传递给后面的函数,函数的返回值会构建成一个新的数组,列表
传入一行数据返回一行数据,总体的数量行数不变
filter方法
将数组,列表中的元素一个一个传递给后面的函数
如果函数返回True保留数据
如果函数返回False过滤数据
数据会变少
sortBy方法
指定一个字段对数据进行排序, 默认是升序
sortWith方法
传入一个比较规则
flatMap方法
将集合中的元素一个一个传递给后面的函数
函数的返回值必须是一个集合
后将返回的集合展开成一个新的集合
将一行数据转换多行数据
相当于sql中的explode
val words: List[String] = lines.flatMap((line: String) => line.split(","))
words.foreach(println)
groupBy方法
指定一个字段进行分组,返回一个Map结构的集合
集合
* list : 有序不唯一
* set : 无序唯一
* Map : kv格式
* Tuple : 元组, 固定长度的集合
List
//构建list
//不可变的list
val list = List(1, 2, 3, 4, 5, 6, 6, 7, 8, 9)
//通过下标获取数据
println(list(4))
//获取头
println(list.head)
//获取最后一个元素
println(list.last)
//取top
println(list.take(2))
//获取不包含第一个元素的所有元素
println(list.tail)
//判断是否为空
println(list.isEmpty)
//返回集合,返回一个新的集合
println(list.reverse)
//去重
println(list.distinct)
//将集合构建成一个字符串,指定分割方式
//和split相反
println(list.mkString(","))
//判断是否包含某一个元素
println(list.contains(1))
println("=" * 100)
//求和
println(list.sum)
//取最大值
println(list.max)
//取最小值
println(list.min)
println("=" * 100)
set
唯一无序
常用的map,flatMap,filter groupBy都有
和顺序相关的方法再set集合中没有
//不可变的集合
val set = Set(1, 2, 2, 1, 2, 2, 3, 4)
println(set)
println(set.mkString(","))
set.foreach(println)
/**
* 集合运算
*
*/
val s1 = Set(1, 2, 3, 4, 5, 6)
val s2 = Set(4, 5, 6, 7, 8, 9)
println(s1 & s2) //交集
println(s1 | s2) //并集
println(s1 &~ s2) //差集
元组
固定长度集合
可以通过_获取数据, 相比较于数组,元组不存在下标越界问题
元组中的元素上限是22个
val t = (1, 2, 3, 4, 5, 10)
println(t._1)
Map
kv格式集合
->: 构建二元组的简写
val map = Map(("001", "张三"), ("002", "李四"), ("003", "王五"), "004" -> "赵六")
println(map)
//可以通过key获取value
println(map("001")) //如果key不存在会报错
println(map.getOrElse("007", "默认值")) //如果key不存在返回默认值
//获取所有的key
println(map.keys)
println(map.values) //所有value
可变集合
可变LIst:listBuffer
拥有list所有的方法,同时可以修改
val listBuffer = new ListBuffer[String]
//增加一个元素
listBuffer.+=("java")
//简写
listBuffer += "spark"
listBuffer += "spark"
//批量插入元素
listBuffer ++= List("1", "2", "3")
println(listBuffer)
//修改
listBuffer(0) = "hadoop"
println(listBuffer)
//删除一个元素
listBuffer -= "spark"
//批量删除
listBuffer --= List("1", "2")
println(listBuffer)
可变Map:HashMap
val hashMap = new mutable.HashMap[String, String]()
//增加元素
hashMap.put("001", "张三")
hashMap.+=(("002", "李四"))
//简写
hashMap += "003" -> "王五"
println(hashMap)
//删除元素
hashMap.remove("001")
hashMap -= "002"
//修改
hashMap += "003" -> "王五1"
println(hashMap)
可变Set:HashSet
不可变set有的方法可变set都有
val hashSet = new mutable.HashSet[String]()
//增加元素
hashSet.add("java")
hashSet += "hadoop"
hashSet += "hadoop"
hashSet += "spark"
hashSet ++= List("1", "2", "3")
println(hashSet)
//删除元素
hashSet.remove("java")
hashSet -= "hadoop"
println(hashSet)
模式匹配
java 中的模式匹配
可以匹配基本数据类型,字符串,枚举
scala中的模式匹配可以匹配基本数据类型,字符串,枚举,对象,匹配类型
//1、匹配基本数据类型
val i = 300
i match {
//匹配项,只有一个可以匹配成功
case 100 => println("i等于100")
case 200 => println("i等于200")
case _ => println("其它")
}
//2、匹配字符串
val s = "java"
s match {
case "java" => println("s等于java")
case "hadoop" => println("s等于hadoop")
case _ => println("其它")
}
//3、匹配对象
case class User(id: String, name: String)
val user = User("001", "张三")
user match {
case User("001", "张三") => println("张三")
case User("002", "李四") => println("李四")
case _ => println("其它")
}
//4、匹配类型
val obj: Any = List("java", "hadoop")
obj match {
//s 代表匹配成功之后的变量,相当于是对匹配成功的对象的引用
case s: String => println(s"obj是一个字符串:$s")
case i: Int => println(s"obj是一个Int类型:$i")
case list: List[String] => println(s"obj是一个集合:$list")
case _ => println("其它类型")
}
/**
* 匹配成功可以有返回值
*
*/
val j = 101
val str: String = j % 2 match {
case 1 => "奇数"
case 0 => "偶数"
}
println(str)
/**
* 5、匹配数组
*
*/
scores
.map(line => line.split(","))
.map {
//匹配数组,需要按照顺序写,需要明确类型
//没有使用的列可以使用下划线占位
case Array(id: String, _: String, sco: String) =>
(id, sco.toInt)
}
.foreach(println)
/**
* 6、模式匹配再map集合上的使用
*
*/
val map = Map("001" -> "张三", "002" -> "李四")
println(map.getOrElse("003", "默认值"))
println(map("001"))
/**
* Option: 可选的值
* 有两个实例
* Some : 有值
* None : 没有值
*
*/
val option: Option[String] = map.get("001")
println(option.get)
val value: String = map.get("001") match {
//有值,返回对应的value
case Some(v) => v
//没有值,返回默认值
case None => "默认值"
}
println(value)
implicit :隐式转换
implicit : 定义隐式转换的关键字
1、隐式转换方法
可以将当前作用域中所有的参数类型的变量转换成返回值类型
隐式转换方法和方法名无关
和参数类型,返回值类型有关
再同一个作用域中只能存在一个参数类型和返回值类型一样的隐式转换方法
implicit def intToString(i: Int): String = {
println("intToString")
i.toString
}
implicit def doubleToString(d: Double): String = {
d.toString
}
fun(1000)
//相当于
//fun(intToString(1000))
fun(3.14)
/**
* 隐式转换的作用 -- 可以动态的给对象增加新的方法
* scala中的String 和java中的String是同一个
* 为什么scala中的String有toInt ,toDouble
* 因为scala会隐式的将String转换成StringLike
*
*/
val ii: Int = "100".toInt
隐式转换类
隐式转换类
可以将构造函数参数类型转换成当前类的类型 – 构造函数参数类型就会多了当前类的方法
隐式转换类和类没那个无关,和构造函数的参数类型有关,和隐式转换的方法名有关
object Demo31Iimplicit {
def main(args: Array[String]): Unit = {
/**
* 隐式转换类
*/
val path = "data/students.txt"
val stus: List[String] = path.load
println(stus)
//简化代码
val scores: List[String] = "data/score.txt".load
}
implicit class Read(path: String) {
def load: List[String] = {
println("读取数据的方法")
Source.fromFile(path).getLines().toList
}
}
}
偏应用函数
def fun(x: Int, y: Int): Int = x * y
println(fun(100, 200))
//再调用函数的时候只传一部分参数,
//后续再指定后面的参数,可以多次使用
val f: Int => Int = fun(100, _: Int)
println(f(200))
println(f(300))
println(f(400))
//相当于
println(fun(100, 200))
println(fun(100, 300))
println(fun(100, 400))
函数柯里化
def fun(x: Int)(y: Int): Int = {
x * y
}
val i: Int = fun(100)(200)
println(i)
//可以先传第一个参数,会返回一个新的函数
val f: Int => Int = fun(100)
println(f(100))
println(f(200))
println(f(300))
/**
* 函数柯里化和隐式转换变量结合起来使用
*
*/
//隐式转换变量
//当一个作用域中只能存在一个同类型的隐式转换变量
implicit val num: Int = 100
def fun2(x: Int)(implicit y: Int): Int = x * y
println(fun2(2)(3))
//会自动将当前作用域中Int类型的隐式转换变量赋值给y
println(fun2(2))
//应用
val source: BufferedSource = Source
.fromFile("data/students.txt")(Codec("utf-8"))
反射
可以通过类对象获取类的方法,构造函数,属性
可以通过获取到的构造函数创建这个类的对象
类对象: 一个class文件再内存中的存在形式, 是CLass这个类的对象
类的对象: 通过new创建的类的对象
下面是一段Java代码通过反射向参数类型为String类型的数组添加Int类型的数据:
public class Demo37 {
public static void main(String[] args) throws Exception {
/*
* 通过反射绕过泛型对类型的限制
*/
ArrayList<String> list = new ArrayList<>();
list.add("java");
list.add("hadoop");
list.add("spark");
System.out.println(list);
//获取类对象
Class<? extends ArrayList> listClass = list.getClass();
//获取add方法
Method add = listClass.getMethod("add", Object.class);
//执行add方法
add.invoke(list, 100);
System.out.println(list);
}
}