样例类
1.使用场景
样例类是一种特殊的类,可以快速定义一个用于保存数据的类
2.定义样例类
case class 名称([var/val] 成员变量名1:类型1,[var/val]成员变量名2:类型2)
- 如果要实现某个成员变量可以被修改,可以添加var
- 默认是val,可以省略不写
package com.ityuge
object CaseClassDemo {
//1.定义一个样例类
case class Person(name:String,age:Int)
//2.创建样例类
def main(args: Array[String]): Unit = {
val zhangsan = Person("张三",20)
println(zhangsan)
}
}
3.样例类的方法
以下方法都是样例类自动实现的方法
(1)apply方法
可以让我们快速的使用类名来创建对象,类名加参数通过scala编译器就会自动使用apply方法帮我们创建对象
(2)toString方法
打印样例类时scala会自动调用toString方法
(3)equals方法
样例类自动实现了equals方法,可以直接使用==比较两个样例类是否相等,即所有的成员变量是否相等
(4)hashCode方法
样例类自动实现了hashCode方法,如果所有的成员变量的值相同,则hash值相同,只要有一个不一样,则hash值不一样
package com.ityuge
object CaseClassDemo {
//1.定义一个样例类
case class Person(name:String,age:Int)
//2.创建样例类
def main(args: Array[String]): Unit = {
val lisi1 = Person("张三",20)
val lisi2 = Person("张三",20)
println(lisi1.hashCode())
println(lisi2.hashCode())
}
}
(5)copy方法
样例类实现了copy方法,可以快速创建一个相同的实例对象
package com.ityuge
object CaseClassDemo {
//1.定义一个样例类
case class Person(name:String,age:Int)
//2.创建样例类
def main(args: Array[String]): Unit = {
val lisi1 = Person("张三",20)
val wangwu = lisi1.copy(name="王五") //这里可以使用带名参数直接去指定name的参数
println(wangwu)
println(lisi1)
}
}
4.样例对象
(1)使用场景
- 定义枚举 (什么是枚举:是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内.)
- 作为没有任何参数的消息传递
(2)样例对象定义
样例对象是单例的,而且他没有主构造器
case object 对象名
package com.ityuge
object CaseClassDemo {
//1.创业一个Sex枚举(样例对象)
trait Sex
//创建两个样例对象从特质进行继承
case object Male extends Sex
case object Female extends Sex
//2.定义一个样例类,使用Sex枚举
case class Person(name:String,sex:Sex)
def main(args: Array[String]): Unit = {
val zhansan = Person("zhansan",Male)
val lisi = Person("lisi",Female)
println(zhansan)
println(lisi)
}
}
模式匹配
scala的模式配置类似于java的swith语句
1.使用场景
- swith语句
- 类型查询
- 使用模式配置快速获取数据
2.简单模式匹配
变量 math{
case "常量1" => 表达式1
case "常量2" => 表达式2
case "常量3" => 表达式3
case _ => 表达式4 //默认匹配
}
package com.ityuge
import scala.io.StdIn
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//1.从控制台读取单词
val input = StdIn.readLine()
//2.使用模式匹配判断单词是否能够模式匹配
val result = input match {
case "hadoop" => "大数据分布式存储计算框架"
case "zookeeper" => "大数据分布式协调框架"
case "spark" => "大数据分布式内存计算框架"
case _ => "未匹配"
}
println(result)
}
}
3.匹配类型
如果我们要根据不同数据类型,来执行不同的逻辑,也可以使用match来实现
变量 match {
case 变量名:类型1 => 表达式1
case 变量名:类型2 => 表达式2
case 变量名:类型3 => 表达式3
case _ => 表达式4
}
package com.ityuge
import scala.io.StdIn
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//1.定义Any类型的变量
//分别赋值:"hadoop",1,1.0
val a:Any = "hadoop"
//2.使用模式匹配匹配数据类型
a match {
case a:Int => println(s"${a}是整型")
case a:String => println(s"${a}是字符串类型")
case a:Double => println(s"${a}是浮点型")
case _ => println("无匹配")
}
}
}
4.匹配样例类
可以使用模式匹配来匹配样例类,从而可以快速获取样例类中的成员数据
package com.ityuge
object CaseClassDemo {
case class Person(name:String,age:Int)
case class Order(id:String)
def main(args: Array[String]): Unit = {
val zhangsan:Any = Person("张三",20)
val order:Any = Order("001")
zhangsan match{
case Person(name,age) => println(s"姓名:${name} 年龄:${age}")
case Order(id) => println(s"订单号为:${id}")
}
}
}
5.匹配:数组,列表,元组
- 匹配数组
package com.ityuge
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//1.定义三个数组用于匹配
val array1 = Array(1,2,3)
val array2 = Array(0)
val array3 = Array(0,1,2,3,4,5)
//使用match进行匹配
array1 match {
case Array(1,x,y) => println(s"匹配三个元素的数字,第一数字为1,其余为${x},${y}")
case Array(0) => println(s"匹配一个元素的数字,元素之为0")
case Array(o,_*) => println("第一个元素为0,数量不固定的数组")
}
}
}
- 匹配列表
package com.ityuge
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//1.定义三个列表用于匹配
val list1 = List(0)
val list2 = List(0,1,1,3,4,4)
val list3 = List(10,11)
//使用match进行匹配
list1 match {
case 0 :: Nil => println("只有一个元素且元素为0的列表")
case 0 :: tail => println("第一个元素为0且数量不固定的列表")
case x :: y ::Nil => println(s"列表只有两个元素${x},${y}")
}
}
}
- 元组
package com.ityuge
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//1.定义两个元组用于匹配
val tuple1 = (1,3,4)
val tuple2 = (3,4,5)
//使用match进行匹配
tuple1 match {
case (1,x,y) => println("配偶三个元素第一元素为1的元组")
case (x,y,5) => println("匹配三个元素且最后元素为5的元组")
}
}
}
6.变量声明中的模式匹配
(1)使用场景
在定义变量时,可以使用模式匹配快速获取数据
(2)获取数组中指定位置的元素
package com.ityuge
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//1.生成数组0-10
val array = (0 to 10).toArray
//2.模式匹配获取第二第三第四个数字
val Array(_,x,y,z,_*) = array
}
}
(3)获取List中的指定位置的元素
package com.ityuge
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//1.生成0-10列表
val list = (0 to 10).toList
//2.模式匹配获取第二第三第四个数字
val List(_,x,y,z,_*) = list
}
}
Option类型
1.使用场景
使用Option类型可以有效的避免空引用异常.当我们返回某些数据时,可以返回一个Option类型来替换
2.定义
Option类型表示可选值,分为Some(x)表示实际的值,None表示没有值
package com.ityuge
object CaseClassDemo {
//1.定义一个相除的方法,会使用Option来封装数据
def div(x:Double,y:Double): Option[Double] ={
if (y==0){
//表示没有数据
None
}
else{
val result = x/y
//some表示有数据
Some(result)
}
}
//2.可以使用模式匹配来判断是否有值
def main(args: Array[String]): Unit = {
val some = div(10.0,2.0)
val none = div(10.0,0)
some match {
case Some(x) => println(x)
case None => println("除零异常")
}
}
}
- 示例2.使用getOrElse获取值
package com.ityuge
object CaseClassDemo {
//1.定义一个相除的方法,会使用Option来封装数据
def dvi(x:Double,y:Double): Option[Double] ={
if (y==0){
//表示没有数据
None
}
else{
val result = x/y
//some表示有数据
Some(result)
}
}
//2.可以使用模式匹配来判断是否有值
def main(args: Array[String]): Unit = {
val some = dvi(10.0,2.0)
val none = dvi(10.0,0)
println(some.getOrElse(0))
println(none.getOrElse(0)) //是空时打印0
}
}
偏函数
1.使用场景
偏函数可以简化函数的定义,配合函数式编程使代码更加优雅,属于一个语法糖(一个参数一个返回值,就用偏函数,例如map,filter)
2.定义
- 没有match的一组case就是一个偏函数
package com.ityuge
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//1.定义一个偏函数
val partialFunction:PartialFunction[Int,String] = {
case 1 => "一"
case 2 => "二"
case 3 => "三"
case _ => "其他"
}
//2.调用偏函数
println(partialFunction(2))
println(partialFunction(4))
}
}
- 示例2
package com.ityuge
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//1.定义一个列表1-10
val list = (1 to 10).toList
//2.使用集合函数式操作来进行数据的转换
val stringsList = 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 => "[_*]"
}
println(stringsList)
}
}
正则
1.使用场景
- 用来匹配数据
2.定义
(1)Regex类
- scala提供了Regex类来定义正则表达式
- 要构造一个Regex类,可以直接使用String类的r方法
- 使用三引号来表示正则表达式,否则还要对正则内的反斜杠进行转义
val regEx = """正则""".r
(2)findAllMatchin方法
- 使用findAllMatchin方法可以获取到所有正则匹配到的字符串
3.正则使用简介
正则 | 相配合的次数 |
---|---|
.点匹配任意字符 | *星号(0-多次) ; +加号(1-多次) |
正则 | 含义 |
---|---|
\反斜杠 | 转义 |
4.示例
(1)邮箱合法性匹配
package com.ityuge
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//1.定义一个Regex正则对象
//qq12344@163.com
val regex = """.+@.+\..+""".r
//2.使用正则进行匹配数据
val emil1 = "qq12345@163.com"
val emil2 = "qq12133@.com"
if (regex.findAllMatchIn(emil1).size==0){
println(emil1+"是一个非法邮箱")
}
else {
println("是一个合法邮箱")
}
}
}
- 使用偏函数实现
package com.ityuge
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//1.定义一个Regex正则对象
//qq12344@163.com
val regex = """.+@.+\..+""".r
//2.使用正则进行匹配数据
val emil1 = "qq12345@163.com"
val emil2 = "qq12133@.com"
val partialFunction:PartialFunction[Int,String] = {
case x if x>=1 => "合法"
case x if x == 0 => "不合法"
}
println(partialFunction(regex.findAllMatchIn(emil1).size))
println(partialFunction(regex.findAllMatchIn(emil2).size))
}
}
(2)找出列表中不合法邮箱
package com.ityuge
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//1.定义一个Regex正则对象
//qq12344@163.com
val regex = """.+@.+\..+""".r
//2.定义一个邮箱列表
val emilList = List("21323212@qq.com","a121sdsd@gmail.com","zhangsan@163.com","123saff.com")
//3.过滤出来不合法的邮箱
val invalidEmailList = emilList.filter {
//过滤出来没有找到
case eml if regex.findAllMatchIn(eml).size == 0 => true
case _ => false
}
println(invalidEmailList)
}
}
(3)邮箱公司匹配
package com.ityuge
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//1.定义一个Regex正则对象
//qq12344@163.com
val regex = """.+@(.+)\..+""".r
//2.定义一个邮箱列表
val emilList = List("21323212@qq.com","a121sdsd@gmail.com","zhangsan@163.com")
//3.
val companyList = emilList.map {
case eml@regex(company) => s"${eml} -> ${company}"
}
println(companyList)
}
}
异常处理
1.捕获异常
try{
//代码
}
catch{
case ex:异常类型1 => //代码
case ex:异常类型2 => //代码
}
finally{
//代码
}
2.捕获除零异常
package com.ityuge
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//使用try...catch来捕获异常
try{
val a = 10/0
}catch {
case ex:Exception => ex.printStackTrace()
}
println("程序继续执行")
}
}
3.抛出异常
package com.ityuge
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//抛出一个异常
throw new Exception("这是一个异常!")
}
}
提取器
1.使用场景
在模式匹配中更加便捷的在模式匹配中提取数据,我们就要用到提取器
2.样例类的模式匹配就自动实现了提取器
package com.ityuge
object CaseClassDemo {
case class Person(name:String,age:Int)
case class Order(id:String)
def main(args: Array[String]): Unit = {
val zhangsan:Any = Person("张三",20)
val order:Any = Order("001")
zhangsan match{
case Person(name,age) => println(s"姓名:${name} 年龄:${age}") //进行了模式匹配
case Order(id) => println(s"订单号为:${id}")
}
}
}
不是所有的类都可以进行这样的样例匹配,是因为样例类自动实现了apply,unapply方法(提取器)
其他类要想支持模式匹配,必须要实现一个提取器
3.定义提取器
如果说要实现一个类的提取器,只需要在该类的伴生对象中实现一个unapply方法(实现的就是解构功能)即可
def upapply(stu:Student):Option[(类型1,类型2,类型3...)] = {
if(stu != null){
Some((变量1,变量2,变量3..))
}
else{
None
}
}
4.示例
package com.ityuge
object CaseClassDemo {
//1.定义一个普通的类
class Student(var name: String, var age: Int)
object Student {
def unapply(student: Student): Option[(String, Int)] = {
if (student != null) {
//返回一个Some封装数据
Some(student.name, student.age)
} else {
None
}
}
}
def main(args: Array[String]): Unit = {
val zhangsan = new Student("张三",20)
zhangsan match {
case Student(name,age) => println(s"姓名${name},年龄${age}")
}
}
}
泛型
1.使用场景
类和特质,方法都可以支持泛型
主要是对一个集合里面多条数据的一个集中类型约束,即泛型定义是什么类型,整个集合(列表,元组,集)所有元素都会统一类型,在传入过程中,非泛型的类型是不能往集合中传的,而传出时,所有数据类型数据类型统一
2.定义泛型方法
def 方法名[泛型名称](..) = {
//..
}
[T]任意数据类型,等于就是没有定义泛型
2.1示例
package com.ityuge
object CaseClassDemo {
//1.定义方法获取数组的中间元素
def getMiddle(array:Array[Int]) = array(array.length / 2)
def main(args: Array[String]): Unit = {
println(getMiddle(Array[Int](1, 2, 3, 4, 5)))
}
}
3.泛型类
class 类[Int](val 变量名:Int)
3.1示例
package com.ityuge
object CaseClassDemo {
//1.创建泛型类包含两个字段
class Pair[T](name:T,sex:T)
def main(args: Array[String]): Unit = {
val hadoop: Pair[String] = new Pair("hadoop","spark")
}
}
4.上下界
(1)使用场景
在定义泛型时,限定必须从哪个类继承,或者必须是哪个类的父类,此时需要使用到上下界
(2)上界定义
[T <: 类型]
(3)上界示例
package com.ityuge
object CaseClassDemo {
//1.创建一个类和他的子类
class Person
class Student extends Person
//2. 创建一个泛型方法,并且给泛型方法指定一个上界
def demo[T <: Person](array: Array[T]) = println(array)
def main(args: Array[String]): Unit = {
demo(Array(new Person))
demo(Array(new Student))
}
}
(4)下界定义
下界必须是某个类的父类
如果类即有上界,又有下界.下界写在前面,上界写在后面
[T >: 类型]
(5)下界示例
package com.ityuge
object CaseClassDemo {
//1.定义类和子类
class Person
class Policeman extends Person
class Superman extends Policeman
def demo[T >: Policeman <: Person](array: Array[T]) = println(array)
def main(args: Array[String]): Unit = {
demo(Array(new Person))
demo(Array(new Policeman))
}
}
5.协变,逆变,非变
(1)使用场景
使带有泛型的类支持类型转换
(2)非变
- 默认的泛型类就是非变
Super类 | Sub类 |
---|---|
Temp[Super] | Temp[Sub] 定义是时括号没有加减号是非变,数据类型转换和其类型的字符类不涉及任何联系,也就不能进行转换 |
(3)协变
class Pair[+T] //增加了加号就说明是支持协变的
Super父类 | Sub子类 |
---|---|
Temp[Super] | Temp[Sub] Sub类是Super类的子类,Temp[Sub]是可以转换成Temp[Super]这个叫非变 |
(4)逆变
class Pair[-T]
Super父类 | Sub子类 |
---|---|
Temp[Super] | Temp[Sub] 父类转子类就叫逆变 |
(5)示例
package com.ityuge
object CaseClassDemo {
//1.创建一个测试类和子类
class Super
class Sub extends Super
//2.分别创建使用协变,逆变,非变的泛型类
//非变
class Temp1[T]
class Temp2[+T]
class Temp3[-T]
def main(args: Array[String]): Unit = {
//协变
val temp3: Temp2[Sub] = new Temp2[Sub]
val temp4:Temp2[Super] = temp3 //子类型赋值父类型
//逆变
val temp5: Temp3[Super] = new Temp3[Super]
val temp6:Temp3[Sub] = temp5 //父类型赋值子类型
}
}
Actor并发(已经被废弃了,作为学习Akka的铺垫)
1.Java并发编程对象Actor蝙蝠编程
ACtor并发编程模型是与java的并发编程完全不一样的一种机制.他是一种不共享数据,依赖消息传递的一种并发编程模式,可以有效避免死锁,资源争夺等情况
java线程模型 | Actor模型 |
---|---|
"共享数据-锁"模型 | 不共享数据 |
每一个object有一个monitor,监视线程对共享数据的访问 | 不共享数据,Actor之间通过Message通讯 |
加锁代码使用synchronized标识 | |
死锁问题 | |
每个线程内部是顺序执行的 | 每个Actor内部是顺序执行的 |
2.创建Actor
- 使用class继承Actor创建(多个相同Actor)
- 使用object继承Actor创建(只创建一个Actor)
- 定义class或者object基础Actor特质
- 重写act方法
- 调用Actor的start方法执行Actor
package com.ityuge
import scala.actors.Actor
object CaseClassDemo {
//1.创建两个Actor,使用class基础的方法来创建
class Actor1 extends Actor {
override def act(): Unit = {
//编写业务代码
//打印1-10
(1 to 10).foreach(println(_))
}
}
class Actor2 extends Actor{
override def act(): Unit ={
//打印1-20
(1 to 20).foreach(println(_))
}
}
def main(args: Array[String]): Unit = {
new Actor1().start()
new Actor2().start()
}
}
3.Actor程序运行流程
- 调用start方法启动Actor
- 自动执行act()方法
- 向Actor方法消息
- act方法执行完成后,程序会调用exit()方法
4.发送消息/接收消息
!? | 发送同步消息,等待返回值 |
---|---|
! | 发现异步消息,没有返回值 |
!! | 发送异步消息,返回值是Future[Any] |
收消息的类 ! 发消息的类(内容字段)
- receive方法接收消息,需要给receive方法传入一个偏函数
package com.ityuge
import scala.actors.Actor
object CaseClassDemo {
//1.创建两个Actor,使用class基础的方法来创建
object ActorSender extends Actor {
override def act(): Unit = {
//使用! 以异步的方式发送字符串信息
ActorReceive ! "你好"
}
}
object ActorReceive extends Actor{
override def act(): Unit ={
receive{
case msg:String => println(msg)
}
}
}
def main(args: Array[String]): Unit = {
ActorSender.start()
ActorReceive.start()
}
}
5.持续接收消息
我们希望ActorReceive能一直接收消息,我们使用一个while循环,来不停的调用receive来接收消息
package com.ityuge
import java.util.concurrent.TimeUnit
import scala.actors.Actor
object CaseClassDemo {
//1.创建两个Actor
//ActorSender 每个一秒发送一个消息
//ActorReceiver 不停的接收消息
object ActorSender extends Actor{
override def act(): Unit = {
while (true){
ActorRecriver ! "你好"
TimeUnit.SECONDS.sleep(1)
}
}
}
object ActorRecriver extends Actor{
override def act(): Unit = {
while (true){
receive{
case msg:String => println(msg)
}
}
}
}
def main(args: Array[String]): Unit = {
ActorSender.start()
ActorRecriver.start()
}
}
5.1loop和react优化接收信息
package com.ityuge
import java.util.concurrent.TimeUnit
import scala.actors.Actor
object CaseClassDemo {
//1.创建两个Actor
//ActorSender 每个一秒发送一个消息
//ActorReceiver 不停的接收消息
object ActorSender extends Actor{
override def act(): Unit = {
while (true){
ActorRecriver ! "你好"
TimeUnit.SECONDS.sleep(1)
}
}
}
object ActorRecriver extends Actor{
override def act(): Unit = {
//使用loop+react来复用线程,提高消息
loop{
react{
case msg:String => println(msg)
}
}
}
}
def main(args: Array[String]): Unit = {
ActorSender.start()
ActorRecriver.start()
}
}
6.发送和接收自定义消息
- 在Actor的act方法中,可以使用sender获取发送者的Actor引用
(1)示例1:同步有返回
package com.ityuge
import scala.actors.Actor
//定义样例类封装消息
case class ReplyMessage(message:String,name:String)
object CaseClassDemo {
//创建Actor,接收消息,回复消息
object MsgActor extends Actor{
override def act(): Unit = {
loop{
react{
case Message(id,message) => println(s"接收到${id},${message}")
//回复消息
sender ! ReplyMessage("张三","我不好")
}
}
}
}
//定义自定义消息
case class Message(id:Int,message:String) //定义一个样例类
def main(args: Array[String]): Unit = {
MsgActor.start()
//发送同步自定义消息
val reply: Any = MsgActor !? Message(1,"我不好")
//打印回复消息
if (reply.isInstanceOf[ReplyMessage]){
println(reply.asInstanceOf[ReplyMessage])
}
}
}
(2)示例2:异步无返回消息
package com.ityuge
import scala.actors.Actor
//定义样例类封装消息
object CaseClassDemo {
object MsgActor extends Actor {
override def act(): Unit = {
//做一个loop+react接收
loop{
react{
case Message(message,company) => println(s"谁啊${message}我是${company}")
}
}
}
}
case class Message(message:String,company:String)
def main(args: Array[String]): Unit = {
MsgActor.start()
MsgActor ! Message("你好","阿里巴巴吧")
}
}
(3)异步有返回的消息
package com.ityuge
import scala.actors.{Actor, Future}
//定义样例类封装消息
object CaseClassDemo {
case class Reply(message:String,name:String)
object MsgActor extends Actor {
override def act(): Unit = {
//做一个loop+react接收
loop{
react{
case Message(message,company) => println(s"谁啊${message}我是${company}")
sender ! Reply("宇哥的人","陈宇")
}
}
}
}
case class Message(message:String,company:String)
def main(args: Array[String]): Unit = {
MsgActor.start()
val reply: Future[Any] = MsgActor !! Message("你好","阿里巴巴吧")
}
}
WordCount案例
使用Actor并发编程实现多文件的单词统计
1.创建MainActor
package com.ityuge
import java.io.File
import scala.actors.Future
object MainActor {
def main(args: Array[String]): Unit = {
//1.加载指定目录的数据文件
val DIR_PATH = "./data/"
val fileNmarList = new File(DIR_PATH).list().toList
//2.将数据文件添加上一个目录
val prefixFileName = fileNmarList.map {
x => DIR_PATH + x
}
//3.打印所有的文件名
println(prefixFileName)
//1.创建Actor
val wordCountActorList = fileNmarList.map {
case fn => new WordCountActor
}
//2.将Actor和文件名关联起来
val actorFileName: List[(WordCountActor, String)] = wordCountActorList.zip(prefixFileName)
println(actorFileName)
//3.启动Actor/发送接收消息
val futureList: List[Future[Any]] = actorFileName.map {
actorFileName =>
var actor = actorFileName._1
//启动Actor
actor.start()
//发送消息到Actor中,发送的是异步还有返回值的消息
val future: Future[Any] = actor !! WordCountTask(actorFileName._2)
future
}
futureList
println(futureList)
//isSet是否设置了值,没有设置值得future数量不等于0就等待,如果没有被设置值得数量等于0就可以退出循环了
while (futureList.filter(! _.isSet).size !=0){}
// //获取future中封装的数据.apply()获取数据,在做一个数据类型转换,样例类
val wordCountResultList = futureList.map(_.apply().asInstanceOf[WordCountResult])
// //获取样例类中封装(是用map的kv对进行封装的,我们可以使用键获取值)的统计结果
val wordCountResultMap = wordCountResultList.map(_.WordCountMap)
println(wordCountResultMap)
}
}
2.创建WordCountActor类
创建WordCountActor类
package com.ityuge
import scala.actors.Actor
import scala.io.Source
class WordCountActor extends Actor{
override def act(): Unit = {
loop{ //接收
react{
case WordCountTask(fileName) => println("接收到任务:对"+fileName+"进行单词统计")
//1.读取文件名得到源文件,对源文件进行操作,使用getLines产生一个源文件迭代器,迭代一次出一行,toList得到一个文本列表
val fileLineContentList: List[String] = Source.fromFile(fileName).getLines().toList
//2.切割字符串,转换为一个个的单词
//fileLineConttentList ["hadoop sqoop hadopp","hadoop hadoop flume",...]
//[hadoop,sqoop,hadoop]
val wordList: List[String] = fileLineContentList.flatMap(_.split(" "))
//3.将单词转换为一个元组
//[("hadoop",1),("sqoop",1),("spark",1)]
val dataTuples: List[(String, Int)] = wordList.map(_ ->1)
//4.分组聚合
//{"hadoop"->[("hadoop",1),("hadoop",1)],"sqoop"->[("sqoop",1)],"spark"->[("spark",1)]}
val groupData: Map[String, List[(String, Int)]] = dataTuples.groupBy(_._1)
//5.聚合计算实现效果:{hadoop->2,sqoop->1}
val wordCountMap: Map[String, Int] = groupData.map{
keyVal => keyVal._1 -> keyVal._2.map(_._2).sum
}
println(wordCountMap)
//6.将统计数据封装到一个样例类中,发送给MainActor
sender ! WordCountResult(wordCountMap)
}
}
}
}
3.创建样例类集中存放的类
package com.ityuge
/**
* 单词统计任务消息
* @param fileName:文件名
*/
case class WordCountTask(fileName:String)
/**
* 封装单词统计结果
* @param WordCountMap:单词在某个文件出现的数量
*/
case class WordCountResult(WordCountMap: Map[String, Int])
4.创建聚合的工具类WordCountUtil
package com.ityuge
object WordCountUtil {
//单词数据合并
def reduce(wordCountList:List[(String,Int)]): Unit ={
//4.分组聚合
//{"hadoop"->[("hadoop",1),("hadoop",1)],"sqoop"->[("sqoop",1)],"spark"->[("spark",1)]}
val groupData: Map[String, List[(String, Int)]] = wordCountList.groupBy(_._1)
//5.聚合计算实现效果:{hadoop->2,sqoop->1}
val wordCountMap: Map[String, Int] = groupData.map{
keyVal => keyVal._1 -> keyVal._2.map(_._2).sum
}
wordCountMap
}
}