1 样例类
样例类是一种特殊类,它可以用来快速定义一个用于保存数据的类(类似于Java POJO类),而且它会自动生成apply方法,允许我们快速地创建样例类实例对象。后面,在并发编程和spark、flink这些框架也都会经常使用它。
1.1 定义样例类
语法结构:
case class 样例类名(成员变量名1:类型1, 成员变量名2:类型2, 成员变量名3:类型3)
示例1:
// 定义一个样例类 // 样例类有两个成员name、age case class CasePerson(name:String, age:Int) // 使用var指定成员变量是可变的 case class CaseStudent(var name:String, var age:Int) object CaseClassDemo { def main(args: Array[String]): Unit = { // 1. 使用new创建实例 val zhagnsan = new CasePerson("张三", 20) println(zhagnsan) // 2. 使用类名直接创建实例 val lisi = CasePerson("李四", 21) println(lisi) // 3. 样例类默认的成员变量都是val的,除非手动指定变量为var类型 //lisi.age = 22 // 编译错误!age默认为val类型 val xiaohong = CaseStudent("小红", 23) xiaohong.age = 24 println(xiaohong) } }
1.2 样例类方法
toString方法
toString返回:样例类名称(成员变量1, 成员变量2, 成员变量3…)
case class CasePerson(name:String, age:Int) object CaseClassDemo { def main(args: Array[String]): Unit = { val lisi = CasePerson("李四", 21) println(lisi.toString) // 输出:CasePerson(李四,21) } }
equals方法
样例类自动实现了equals方法,可以直接使用==比较两个样例类是否相等,即所有的成员变量是否相等
val lisi1 = CasePerson("李四", 21) val lisi2 = CasePerson("李四", 21) println(lisi1 == lisi2) // 输出:true
hashCode方法
样例类自动实现了hashCode方法,如果所有成员变量的值相同,则hash值相同,只要有一个不一样,则hash值不一样。
val lisi1 = CasePerson("李四", 21) val lisi2 = CasePerson("李四", 22) println(lisi1.hashCode()) println(lisi2.hashCode())
copy方法
样例类实现了copy方法,可以快速创建一个相同的实例对象,可以使用带名参数指定给成员进行重新赋值。
val lisi1 = CasePerson("李四", 21) val wangwu = lisi1.copy(name="王五") println(wangwu)
1.3 样例对象
使用case object可以创建样例对象。样例对象是单例的,而且它没有主构造器。样例对象是可序列化的。格式:
case object 样例对象名
它主要用在两个地方:
- 定义枚举
- 作为没有任何参数的消息传递(后面Akka编程会讲到)
示例:定义枚举
trait Sex /*定义一个性别特质*/ case object Male extends Sex // 定义一个样例对象并实现了Sex特质 case object Female extends Sex case class Person(name:String, sex:Sex) object CaseClassDemo { def main(args: Array[String]): Unit = { val zhangsan = Person("张三", Male) println(zhangsan) } }
示例:定义消息
case class StartSpeakingMessage(textToSpeak: String) // 消息如果没有任何参数,就可以定义为样例对象 case object StopSpeakingMessage case object PauseSpeakingMessage case object ResumeSpeakingMessage
样例类可以使用**类名(参数1, 参数2…)**快速创建实例对象
定义样例类成员变量时,可以指定var类型,表示可变。默认是不可变的
样例类自动生成了toString、equals、hashCode、copy方法
样例对象没有主构造器,可以使用样例对象来创建枚举、或者标识一类没有任何数据的消息
2 模式匹配
scala中有一个非常强大的模式匹配机制,可以应用在很多场景:
- switch语句
- 类型查询
- 以及快速获取数据
2.1 简单匹配
在Java中,有switch关键字,可以简化if条件判断语句。在scala中,可以使用match表达式替代。
语法结构:
变量 match { case "常量1" => 表达式1 case "常量2" => 表达式2 case "常量3" => 表达式3 case _ => 表达式4 // 默认匹配 }
示例1:
println("请输出一个词:") // StdIn.readLine表示从控制台读取一行文本 val name = StdIn.readLine() val result = name match { case "hadoop" => s"$name:大数据分布式存储和计算框架" case "zookeeper" => s"$name:大数据分布式协调服务框架" case "spark" => s"$name:大数据分布式内存计算框架..." case _ => s"未匹配到$name" } println(result)
match表达式是有返回值的,可以将match表达式对其他的变量进行赋值
2.2 守卫
在Java中,只能简单地添加多个case标签,例如:要匹配0-7,就需要写出来8个case语句。例如:
int a = 0; switch(a) { case 0: a += 1; case 1: a += 1; case 2: a += 1; case 3: a += 1; case 4: a += 2; case 5: a += 2; case 6: a += 2; case 7: a += 2; default: a = 0; }
在scala中,可以使用守卫来简化上述代码——也就是在case语句中添加if条件判断。
示例:
println("请输入一个数字:") var a = StdIn.readInt() a match { case a1 if a >= 0 && a <= 3 => a += 1 case a2 if a > 3 && a < 8 => a += 2 case _ => a = 0 } println(a)
2.3 匹配类型
match表达式还可以进行类型匹配。
语法格式如下:
变量 match { case 类型1变量名: 类型1 => 表达式1 case 类型2变量名: 类型2 => 表达式2 case 类型3变量名: 类型3 => 表达式3 ... case _ => 表达式4 }
示例:
// stripMargin表示删除前面的竖线,这样看起来会显得比较整齐 val prompt = """ |0:字符串类型 |1:整形 |2:浮点型 |3:Person对象类型 | |请选择: """.stripMargin println(prompt) val select = StdIn.readInt() val selectedValue = select match { case 0 => "hello" case 1 => 1 case 2 => 2.0 case _ => new Person("张三") } selectedValue match { case x: Int => println("Int " + x) case y: Double => println("Double " + y) case z: String => println("String " + z) case _ => throw new Exception("not match exception") }
2.4 匹配集合
匹配数组
示例:
val arr = Array(1, 3, 5) arr match { case Array(1, x, y) => println(x + " " + y) case Array(0) => println("only 0") case Array(0, _*) => println("0 ...") case _ => println("something else") }
匹配列表
示例:
val lst = List(3, -1) lst match { case 0 :: Nil => println("only 0") case x :: y :: Nil => println(s"x: $x y: $y") case 0 :: tail => println("0 ...") case _ => println("something else") }
匹配元组
示例:
val tup = (1, 3, 7) tup match { case (1, x, y) => println(s"1, $x , $y") case (_, z, 5) => println(z) case _ => println("else") }
2.5 变量声明中的模式匹配
在定义变量的时候,可以使用模式匹配快速获取数据。
示例:获取数组中的元素
val arr = Range(0, 10).toArray arr.foreach(println(_)) // 使用模式匹配,获取第二个、第三个、第四个元素的值 val Array(_, x, y, z, _*) = arr println(s"x=$x, y=$y, z=$z, ")
示例:获取List中的数据
val list = Range(0, 10).toList // 匹配列表的第一个、第二个元素的值 val x::y::tail = list println(s"x=$x, y=$y")
2.6 匹配样例类
scala可以使用模式匹配来匹配样例类,从而可以快速获取样例类中的成员数据。后续,我们在开发Akka案例时,还会用到。
示例:
// 定义样例类 case class SubmitTask(id: String, name: String) case class HeartBeat(time: Long) case object CheckTimeOutTask val msg1 = SubmitTask("001", "task-001") val msg2 = HeartBeat(1000) val msg3 = CheckTimeOutTask val list = List(msg1, msg2, msg3) list(2) match { case SubmitTask(id, name) => println(s"id=$id, name=$name") case HeartBeat(time) => println(s"time=$time") case CheckTimeOutTask => println("检查超时") }
示例:可以使用@符号分隔case语句,用来获取用于匹配的整个示例对象
list(0) match { // obj表示获取用于匹配的样例对象,而id,name表示获取样例中的元素 case obj @ SubmitTask(id, name) => println(s"id=$id, name=$name");println(s"样例类:$obj") case HeartBeat(time) => println(s"time=$time") case CheckTimeOutTask => println("检查超时") }