一、作业代码
/*** @Author laoyan* @Description TODO* @Date 2022/5/5 10:07* @Version 1.0*/object _HomeWork01 {class PC {var cpu:String = _var neicun:String = _var yingpan:String = _def getDetails():Unit = {println(s"$cpu,$neicun,$yingpan")}}class XiaoMi extends PC {var brand: String = _override def getDetails(): Unit = {println(s"$cpu,$neicun,$yingpan,$brand")}}//使用Scala OOP实现台式机、笔记本、平台电脑与Computer之间的关系def main(args: Array[String]): Unit = {val pc = new PC/* pc.cpu = "12核"pc.neicun="32G"pc.yingpan="1T"*/val mi = new XiaoMimi.cpu = "12核"mi.neicun="32G"mi.yingpan="1T"mi.brand ="小米"mi.getDetails()}}
/*** @Author laoyan* @Description TODO* @Date 2022/5/5 10:16* @Version 1.0*/class Point(x:Int,y:Int){}object Point{def apply(x:Int,y:Int) = new Point(x,y)}object _HomeWork02 extends App{// 定义一个Point类和一个伴生对象,使得我们可以不用new而直接用Point(3,4)来构造Point实例val point: Point = Point(3, 4)}
/*** @Author laoyan* @Description TODO* @Date 2022/5/5 10:19* @Version 1.0*/// App 是可以接收 args 参数的 args: Array[String]// 使用idea 传递参数有点问题?????object _HomeWork03 extends App{// 编写一个Scala应用程序Reverse,使用App特质,以反序打印命令行参数,// 用空格隔开。举例来说,运行“Hello World”应该打印World Hello`。for(str <- args.reverse) println(_)}
二、样例类
case class 类名([var/val]成员变量1:类型1,....) {}默认如果不写的话 ,默认就是val ,可以省略如果成员变量需要被修改的话,使用var
/*** @Author laoyan* @Description TODO* @Date 2022/5/5 10:33* @Version 1.0*/object _01样例类 {/*** 样例类有点类似于我们的 pojo (实体)* 样例类进行实例化的时候,不需要编写 new 关键字* 以前要达到这个不写new 就可以得到一个对象的方法只有一个:* 需要编写这个类对应的伴生对象,并且在伴生对象中,还需要编写 apply 方法**/// 样例类中,如果变量前面不加 var val 默认是val的case class Person(name:String,age:Int)class Person2(name:String,age:Int)case class Person3(var name:String,age:Int)def main(args: Array[String]): Unit = {val person = Person("张三", 20)// person.name = "李四" 此处会报错,因为 name使用的是val修饰的val person2 = new Person2("张三", 20)println(person)val person3 = Person3("张三", 20)person3.name = "李四" // 此处就是正确的,因为使用var 修饰变量}}
/*** @Author laoyan* @Description TODO* @Date 2022/5/5 10:43* @Version 1.0*/object _02样例类中的方法 {/*** 样例类中,有很多默认的方法,不需要我们自己编写就有的* apply 方法* toString* equals* hashCode* copy*/case class CasePerson(name:String,age:Int)def main(args: Array[String]): Unit = {val person: CasePerson = CasePerson("老闫", 20)println(person) // 打印对象,就是打印对象中的toString 方法println(person.toString) // 这个是样例类中默认的打印方式// 如何知道使用了apply方法,// 因为我们一个类,不需要new 就可以得到这个类的实例化对象,这个现象本身就说明了使用apply方法// equals 等同于 ==var lisi1 = CasePerson("lisi", 20)var lisi2 = CasePerson("lisi", 20)// equals 比较的是 两个对象的值,只要值完全一样,就相等,否则不能println(lisi1.equals(lisi2)) // 在输出的地方输入prtln trueprintln(lisi1 == lisi2) // true// eq 比较的是两个对象的内存地址println(lisi1 .eq(lisi2) ) // false// 样例类也自动实现了hashCode 只要两个类中的值完全一样,hashCode 就一样println(lisi1.hashCode())println(lisi2.hashCode())// copy 方法,可以快速的创建相同的实例对象,也可以使用带名的参数重新赋值var lisi3 = CasePerson("lisi", 20)// 拷贝了一个值完全相等,但是地址还是不一样的对象val lisi4: CasePerson = lisi3.copy();println(lisi3.eq(lisi4))val lisi5: CasePerson = lisi3.copy(age=25);println(lisi5)}}
三、样例对象

样例对象,首先没有样例类常用。
1、定义枚举
2、进行消息的传递(Akka编程)
case object 类名
样例对象肯定是单例的了,而且没有主构造器
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 11:26
* @Version 1.0
*/
// 样例类经常当做枚举使用
trait Sex // 特质
case object Male extends Sex
case object Female extends Sex
case class Student(name:String,sex:Sex)
object _03样例类 {
def main(args: Array[String]): Unit = {
val student: Student = Student("老闫", Male)
println(student)
}
}
四、模式匹配(重点)
scala有强大的模式匹配机制,可以应用于多个场景:
1、switch
2、类型查询(类型匹配)
3、可以快速获取数据
简单的模式匹配:
类似于java中的switch 在scala中,使用match 表达式替代
变量 match {
case "变量1" => 表达式1
case "变量2" => 表达式2
case "变量3" => 表达式3
case _ => 表达式 // 表示什么都没有匹配上的处理
}
import scala.io.StdIn
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 11:36
* @Version 1.0
*/
object _04简单的模式匹配 {
def main(args: Array[String]): Unit = {
val str: String = StdIn.readLine()
str match {
case "春" => println("春困")
case "夏" => println("热")
case "秋" => println("秋乏")
case "冬" => println("冷")
case _ => println("你不适合学习")
}
// 模式匹配是有返回值的,默认就是你语句的最后一句话
val str1: String = str match {
case "春" => "chun"
case "夏" => "xia"
case "秋" => "qiu"
case "冬" => "dong"
case _ => "ni zou!"
}
println(str1)
}
}
类型匹配:
变量 match {
case 类型1变量名:类型1 => 表达式1
case 类型2变量名:类型2 => 表达式2
case 类型3变量名:类型3 => 表达式3
case _ => 表达式 // 表示什么都没有匹配上的处理
}
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 11:45
* @Version 1.0
*/
object _05类型匹配 {
def main(args: Array[String]): Unit = {
// 只看数据类型即可,跟值无关
val a:Any = 10
val str: String = a match {
// 如果case 表达式中无需使用到匹配的变量,可以使用下划线代替
case _: String => "String类型的数据"
case _: Int => "Int类型的数据"
case _: Double => "Double类型的数据"
}
println(str)
}
}
模式匹配中的守卫:
在scala中,可以使用守卫来简化我们的代码(可以在case语句中添加条件的判断)
import scala.io.StdIn
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 11:54
* @Version 1.0
*/
object _06模式匹配之守卫 {
def main(args: Array[String]): Unit = {
val a = StdIn.readInt();
a match {
case 1 => println("[0~3]")
case 2 => println("[0~3]")
case 3 => println("[0~3]")
case 4 => println("[4~8]")
case 5 => println("[4~8]")
case 6 => println("[4~8]")
case 7 => println("[4~8]")
case 8 => println("[4~8]")
}
//可以通过守卫的模式进行简化
a match {
case _ if a>=0 && a <=3 => println("[0~3]")
case _ if a>=4 && a <=8 => println("[4~8]")
}
}
}
模式匹配之样例类(case class):
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 12:01
* @Version 1.0
*/
case class PersonP(name:String,age:Int)
case class Order(id:String)
object _07模式匹配样例类 {
def main(args: Array[String]): Unit = {
val person: Any = PersonP("老闫", 30)
val order: Any = Order("28394829384324")
order match {
case PersonP(name,age) => println(s"$name,$age")
case Order(id) => println(s"订单编号是$id")
case _ => println("不是以上两种类型")
}
}
}
模式匹配之匹配集合
可以匹配数组,list,以及元组
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 12:09
* @Version 1.0
*/
object _08模式匹配之集合 {
def main(args: Array[String]): Unit = {
// 数组案例
var arr = Array(1,3,4)
arr match {
case Array(1,x,y) => println(s"${x},${y}")
case Array(0) => println("该数组中只有一个0")
case Array(0,_*) => println("0 ......")
case _ => println("没有匹配到任何的类型")
}
// 匹配list集合
val list = List(0,2, 3)
list match {
case 0::Nil => println("该list中只有一个0")
case 0::tail => println("该list第一个是0,后面还有很多的值")
case x:: y :: Nil => println(s"list集合中只有两个值,${x},${y}")
case _ => println("没有匹配到任何的类型")
}
// 匹配元组
val tuple = (2,3,5)
tuple match {
// 匹配模式,如果可以匹配多个值,先匹配哪个就执行哪个,后面不执行
case (1,x,y) => println(s"元组中有三个值,1开头,另外两个是${x},${y}")
case (x,y,5) => println(s"元组中有三个值,5结尾,另外两个是${x},${y}")
case _ => println("没有匹配到任何的类型")
}
}
}
变量中的模式匹配:
可以通过模式匹配快速获取数据
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 14:38
* @Version 1.0
*/
object _09变量模式匹配 {
def main(args: Array[String]): Unit = {
// 获取数组中的元素
var arr = (1 to 10).toArray
// 通过模式匹配获取 数组中的 第二第三第四个值
var Array(_,x,y,z,_*) = arr
println(x,y,z)
var list = (1 to 10).toList
val a::b::tail = list
println(a,b)
}
}
五、Option 类型
一般是将数据存放到option类型中,需要的时候获取出来。
可以有效的避免null(空指针异常):
有两种数据形式:
Option 是一个总称,里面有两种数据的类型,一个Some 一个None
Some(x) : 表示实际的值
None: 表示没有值
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 14:48
* @Version 1.0
*/
object _10Option数据类型 {
// 编写一个两个数相除的方法
def dvi(a:Double,b:Double) = {
if(b != 0){
Some(a / b)
}else{
None
}
}
def main(args: Array[String]): Unit = {
val op: Option[Double] = dvi(10, 5)
/*op match {
case Some(x) => println(x)
case None => println("除0异常")
}*/
// 可以使用getOrElse 方法,如果为None,可以给定默认值
println(op.getOrElse(0))
}
}
六、偏函数
偏函数是一种简写的方式。
偏函数被包在{} 内,没有 match 的一组 case 语句就是偏函数
语法:
PartialFuction[A,B]
A: 输入的数据类型
B: 代表输出的数据类型
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 14:59
* @Version 1.0
*/
object _11偏函数 {
def main(args: Array[String]): Unit = {
// 首先是 {} 括起来
// 没有match 只有case
// val func1: PartialFunction[Int,String]
val func1: PartialFunction[Int,String] = {
case 1 => "一"
case 2 => "二"
case 3 => "三"
}
println(func1(2))
val list: List[Int] = (1 to 10).toList
val list2: List[String] = list.map({
case x if x >= 1 && x <= 3 => "[1~3]"
case x if x >= 4 && x <= 8 => "[4~8]"
case x if x > 8 => "(8~]"
})
// 以上方法可以简化为:
// map 中传递了一个偏函数,此时可以省略()
val list3: List[String] = list.map{
case x if x >= 1 && x <= 3 => "[1~3]"
case x if x >= 4 && x <= 8 => "[4~8]"
case x if x > 8 => "(8~]"
}
println(list3)
}
}
七、正则表达式
var regex = """正则表达式""".r
findAllMatchIn 方法
可以获取到所有正则匹配到的字符串
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 15:12
* @Version 1.0
*/
object _12正则表达式 {
def main(args: Array[String]): Unit = {
// 邮箱的正则 8383@qq.com
val regex = """.+@.+\..+""".r
val email1 = "34343@163.com"
val email2 = "xxxxxx@com"
if(regex.findAllMatchIn(email1).size >0 ){
println("邮箱合法")
}else{
println("邮箱不合法")
}
if(regex.findAllMatchIn(email2).size >0 ){
println("邮箱合法")
}else{
println("邮箱不合法")
}
// 给定一堆的 邮箱,校验哪些是正确的邮箱
val emailList = List("32343@qq.com","23sfs3re@gmail.com","zhangsanlisi@yeah.net","32333.com");
val hefaEmailList: List[String] = emailList.filter(x => if (regex.findAllMatchIn(x).size > 0) true else false)
println(hefaEmailList)
// 需求升级了,获取合法的邮箱以及运营商名称
val regex2 = """.+@(.+)\..+""".r // 跟之前相比,多了一个括号,这个括号叫做匹配分组
// map 方法,可以将list集合中的数据,一个个的执行函数(此处是偏函数) --> 得到一个新的list集合
val newList: List[String] = emailList.map ({
case x @ regex2(yunyingshang) => s"${x}->${yunyingshang}"
case x => x + "=> 未知运营商"
})
println(newList)
}
}
八、异常处理
异常处理的基本用法:
import scala.util.control.Exception
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 15:38
* @Version 1.0
*/
object _13异常处理 {
/**
* try{
*
* }catch{
* case ex:异常类型1 => 执行某代码
* case ex:异常类型2 => 执行某代码
* }
* finally {
*
* }
*
*/
def yichang(){
/**
* 遇到某个问题,我们也可以抛异常,这个异常抛出后,不需要在方法上继续throws
* java 中的throws 设计被认为是设计上的失败
*/
throw NullPointerException;
}
def main(args: Array[String]): Unit = {
try{
var i = 10 / 0;
}catch{
case ex:ArithmeticException => println(ex.getMessage)
case ex:NullPointerException => println("有空指针了,快处理")
}finally {
println("不管怎样,我都会执行的")
}
println("是否继续运行呢")
yichang()
}
}
九、提取器
样例类可以进行模式匹配,但是我们自己写的普通类,是无法进行模式匹配的,为了使我们的普通类也可以进行模式匹配,普通类需要添加提取器。
普通类需要定义提取器才能进行模式匹配:
apply 方法
变量1
变量2
.....
通过apply 方法进行构造 成一个 对象
对象 --> unapply(解构) --> 变量一,变量二.....
如何实现一个类的提取器:
只需要在这个类的伴生对象中,实现unapply方法即可
def unapply(stu:Student):Option[(类型1,.....)] ={
Some((变量1,变量2.....))
}
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 16:15
* @Version 1.0
*/
object _14提取器 {
class Student(var name:String,var age:Int)
object Student {
// 构造
def apply(name:String, age:Int)={
new Student(name,age)
}
// 伴生对象中的解构方法
def unapply(student: Student) = {
if(student != null){
var tuple = (student.name,student.age)
Some(tuple)
}else{
None
}
}
}
def main(args: Array[String]): Unit = {
val zhangsan = Student("张三", 20)
zhangsan match {
case Student(name,age) => println(s"$name,${age}")
}
}
}
十、泛型
1、方法上添加泛型
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 16:31
* @Version 1.0
*/
object _15泛型 {
/*def getMiddle(arr:Array[Int]) = {
arr(arr.length /2)
}*/
/**
* 编写方法的时候,我们不指定返回值类型
* def 方法名字[泛型] () = {
*
* }
*/
def getMiddle[T](arr:Array[T]) = {
arr(arr.length /2)
}
// 升级需求:不管这个数组是什么类型,都可以获取中间的值
def main(args: Array[String]): Unit = {
val arr: Array[Int] = Array(1, 3, 5, 6, 8)
println(getMiddle(arr))
val arr2: Array[String] = Array("1"," 3"," 5", "6", "8")
println(getMiddle(arr2))
}
}
2、类上可以添加泛型
class 类名[T](val 变量名:T)
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 16:40
* @Version 1.0
*/
case class Pair[T](var a:T,var b:T)
object _16类上添加泛型 {
def main(args: Array[String]): Unit = {
val list = List(
Pair("Spark", "Storm"),
Pair(10, 20)
)
println(list)
}
}
3、泛型的上下界
定义上界:
语法
[T <: 类型]
定义一个泛型的上界,这个泛型的参数必须是这个类本身或者是继承字这个类
定义下界:
[T >: 类型]
该类型必须是某个类的父类(也可以是自己本身)
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 16:47
* @Version 1.0
*/
class Personn
class Studentt extends Personn
class XiaoXueSheng extends Studentt
object _17泛型的上下界 {
/*
如果一个泛型中,既有下边界,又有上边界,先写下界,在写上界
*/
def fangFaA[T <: Personn](a:Array[T]) = println(a)
def fangFaB[T >: Studentt](a:Array[T]) = println(a)
def main(args: Array[String]): Unit = {
fangFaA(Array(new Personn))
fangFaA(Array(new Studentt))
fangFaA(Array(new XiaoXueSheng))
// d type arguments [String] do not conform to method fangFaA's type parameter bounds [T <: Person]
//fangFaA(Array("laoyan"))
fangFaB(Array(new Personn)) // 正确
fangFaB(Array(new Studentt)) // 正确
//fangFaB(Array(new XiaoXueSheng)) //错误
}
}
4、协变、逆变、非变
spark中经常在源代码中出现 协变、逆变、非变
非变:
class pair[T]{}
默认的泛型都是非变的。
类型B是类型A的子类, 但是 pair[A] pair[B] 没有任何关系 == 非变
pari[Person] pair[Student] 他们之间只有泛型有继承关系,但是类没有任何的关系。
var a = new Pari[Person];
var b = new Pair[Student];
a b 之间没有任何关系。
协变:
class Pair[+T]
类型B是类型A的子类,Pair[B] 可以认为是 Pair[A] 的子类型
逆变:
class Pair[-T]
类型B是类型A的子类,Pair[A] 反过来可以认为 是Pair[B] 的子类型
/**
* @Author laoyan
* @Description TODO
* @Date 2022/5/5 17:11
* @Version 1.0
*/
class Super
class Sub extends Super
// 非变
class Temp1[T]
// 协变
class Temp2[+T]
// 逆变
class Temp3[-T]
object _17协变逆变非变 {
def main(args: Array[String]): Unit = {
val a:Temp1[Sub] = new Temp1[Sub]
//编译报错,两者之间没有关系
//var b:Temp1[Super] = a;
val c:Temp2[Sub] = new Temp2[Sub]
// 协变
var d:Temp2[Super] = c;
val e:Temp3[Super] = new Temp3[Super]
//逆变
val f:Temp3[Sub] = e;
}
}
