大数据基础-scala样例类,模式匹配,Option类型,偏函数,正则,异常处理,提取器,泛型,Actor并发变成,WordCount案例

scala的API文档

目录标题

样例类

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)
  1. 定义class或者object基础Actor特质
  2. 重写act方法
  3. 调用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程序运行流程

  1. 调用start方法启动Actor
  2. 自动执行act()方法
  3. 向Actor方法消息
  4. 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)
  }
}

相关java的File的使用

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
  }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值