25 scala 进阶

文章目录

  • scala 进阶
    • 1.高阶函数
      • 1.1 函数作为参数的函数
      • 1.2 匿名函数
      • 1.3 高阶函数
      • 1.4 高阶函数作为方法的返回类型
      • 1.5 参数类型推断
      • 1.6 闭包与柯里化
    • 2.scala当中的类
      • 2.1 类的定义与创建
      • 2.2 类的实例化以及使用
      • 2.3 属性的getter和setter方法
      • 2.4 类的构造器
    • 3.scala当中的对象
      • 3.1 scala当中的Object
      • 3.2 伴生类与伴生对象
      • 3.3 scala当中的apply方法
      • 3.4 scala当中的main方法
      • 3.5 枚举
    • 4.scala当中的继 承
      • 4.1 Scala中继承(extends)的概念
      • 4.2 Scala中override 和 super 关键字
      • 4.3 Scala中isInstanceOf 和 asInstanceOf
      • 4.4 Scala中getClass 和 classOf
      • 4.5 Scala中使用模式匹配进行类型判断
      • 4.6 Scala中protected (了解)
      • 4.7 Scala中调用父类的constructor
      • 4.8 Scala中抽象类
    • 5.scala当中的特质trait
      • 5.1 将trait作为接口使用
      • 5.2 在trait中定义具体的方法
      • 5.3 在trait中定义具体field
      • 5.4 在trait中定义抽象field
      • 5.5 在实例对象指定混入某个trait
      • 5.6 trait 调用链
      • 5.7 混合使用 trait 的具体方法和抽象方法
      • 5.8 trait的构造机制
      • 5.9 trait 继承 class (java中接口不能)
      • 5.10 scala当中的特质总结
    • 6.模式匹配和样例类
      • 6.1 字符匹配
      • 6.2 匹配字符串
      • 6.3 守卫
      • 6.4 匹配类型
      • 6.5 匹配数组、元组、集合
      • 6.6 样例类
      • 6.7 偏函数
    • 7.scala当中的类型参数(了解)
      • 7.1 scala当中的类的泛型
      • 7.2 函数的泛型
      • 7.3 scala当中的上下界之泛型类型的限定
      • 7.4 scala当中的视图界定
      • 7.5 scala当中的协变,逆变和非变
    • 8.scala当中的Actor并发编程
      • 8.1 scala当中的Actor介绍
      • 8.2 Actor实战
        • 第一个例子
        • 第二个例子 实现发送,接收消息
        • 第三个例子 实现actor可以不断地接受消息
        • 第四个例子 使用react方法代替receive方法去接受消息
        • 第五个例子 结合case class样例类发送消息和接受消息
        • 练习实战 用actor并发编程写一个单机版的WordCount
    • 9.scala当中的文件操作和网络请求
      • 9.1 读取文件当中每一行的数据
      • 9.2 读取词法单元和数字
      • 9.3 读取网络资源、文件写入、控制台操作
      • 9.4 scala当中的序列化
      • 9.5 scala当中的正则表达式
    • 10.隐式转换和隐式参数
      • 10.1 隐式转换
      • 10.2 隐式参数
      • 10.3 隐式转换作用域与时机
      • 10.4 隐式转换和隐式参数案例
        • 隐式转换案例一(将我们的Double类型的数据自动转换成Int类型)
        • 隐式转换案例二(让File类具备RichFile类中的read方法)
        • 隐式转换案例三(超人变身)
        • 隐式转换案例四(一个类隐式转换成具有相同方法的多个类)
        • 隐式参数案例五(员工领取薪水)
    • 11.scala编程实战
      • 11.1 使用Akka实现一个简易版的spark通信框架
      • 11.2 项目概述
      • 11.3 项目实现
        • 实战一 利用Akka的actor编程模型,实现2个进程间的通信。
          • 架构图
          • 重要类介绍
          • Actor
          • 具体代码
            • 第一步:创建maven工程,导入jar包
            • 第二步:master进程代码开发
            • 第三步:worker进程代码开发
        • 实战二 使用Akka实现一个简易版的spark通信框架
          • 架构图
          • 具体代码
            • ① Master类
            • ② Worker类
            • ③ WorkerInfo类
            • ④ 样例类

scala 进阶

1.高阶函数

1.1 函数作为参数的函数

使用函数作为参数的方法,叫做高阶函数

package cn.itcast.scala

object ScalaTest {
     


  val myFunc = (x:Int) => {
     x*x}
  def main(args: Array[String]): Unit = {
     
    //方法就是函数,函数就是对象
    def myMethod(x:Int) : Int = {
     x*x}

    val myArray0 = Array(1,3,5,7,9).map(x => x*x)   //匿名函数优先使用
    val myArray1 = Array(1,3,5,7,9).map(myFunc)     //函数就是对象
    val myArray2 = Array(1,3,5,7,9).map(myMethod)   //方法就是函数
    val myArray3 = Array(1,3,5,7,9).map(_*2)        //实现不了x*x功能 因为x出现了两次,不能使用_
    println(myArray0.mkString(","))
    println(myArray1.mkString(","))
    println(myArray2.mkString(","))
    println(myArray3.mkString(","))
  }

}

1.2 匿名函数

package cn.itcast.scala

object ScalaTest {
     
  def main(args: Array[String]): Unit = {
     
    println((x:Int,y:Int) => {
     x * y})   // 
  }
}

1.3 高阶函数

package cn.itcast.scala

object ScalaTest {
     


  def main(args: Array[String]): Unit = {
     
    val func3: (String, Int) => (Int, String) = {
     
      (x, y) => (y + 2, x + "hello")
    }

                    //函数匿名函数定义第二种方式
    def myMethod3(hello: (String, Int) => (Int, String)): Int = {
     
      val result: (Int, String) = hello("zhangsan", 60)
      result._1
    }

    val result: Int = myMethod3(func3)
    println(result)   //62
  }
}

1.4 高阶函数作为方法的返回类型

package cn.itcast.scala

object ScalaTest {
     


  def main(args: Array[String]): Unit = {
     
    def myFunc4(x:Int) = {
     
      //方法的最后返回值,是一个匿名函数
      (y:String) =>y + x
    }
    println(myFunc4(50))	//
  }
}

1.5 参数类型推断

package cn.itcast.scala

object ScalaTest {
     


  def main(args: Array[String]): Unit = {
     
    val myArray = Array(1, 3, 5, 7, 9)
    //map当中需要传入一个函数,我们可以直接定义一个函数
    println(myArray.map((x: Int) => x * 2).mkString("==="))
    //进一步化简 参数推断省去类型信息
    println(myArray.map((x) => x * 2).mkString("==="))
    //进一步化简  单个参数可以省去括号
    println(myArray.map(x => x * 2).mkString("==="))
    ///进一步化简  如果变量只在=>右边只出现一次,可以用_来代替
    println(myArray.map(_ * 2).mkString("==="))
    /*
    2===6===10===14===18
	2===6===10===14===18
	2===6===10===14===18
	2===6===10===14===18
    *\
  }
}

1.6 闭包与柯里化

package cn.itcast.scala

object ScalaTest {
     


  def main(args: Array[String]): Unit = {
     
    //柯里化 柯里化定义形式
    def kery(x:Int)(y:Int) = {
     
      x+y
    }

    val kery1: Int = kery(30)(20)
    println(kery1)

    val keryResult = (x:Int) => {
      (y:Int) => {
     x + y} } // 函数的返回值也是函数,为function1,切内部是匿名函数无法赋值
    println(keryResult(10))
                     //keryResult(20) => 匿名函数  y:Int => 20+y <=1,3,5,7,9
    val myArray = Array(1,3,5,7,9).map(keryResult(20))
    println(myArray.toBuffer) //ArrayBuffer(21, 23, 25, 27, 29)

    //柯里化推导过程
    //柯里化守门Scala面向函数式编程,必然导致的一种结果
    def keryMethod(x:Int) = {
     
      //里面的函数,将外面的参数包起来了,叫做闭包
      y:Int => {
     y + x}
    }
    keryMethod(30)
    
  }
}

总结:
函数可以用来干嘛 ==>
1.作为一个方法的参数
2.函数可以直接调用
3.匿名函数无法调用,但是可以通过作为一个方法的参数进行赋值调用如

Array(1,3,5,7,9).map(keryResult(20))

2.scala当中的类

2.1 类的定义与创建

package cn.itcast.scala

class Person {
     
  //定义一个属性,叫做name的,使用val不可变量来进行修饰
  // 用val修饰的变量是可读属性,有getter但没有setter(相当与Java中用final修饰的变量)自动生成该方法
  val name:String ="zhangsan"
  //定义一个属性,叫做age的,使用var可变量来进行修饰
  //用var修饰的变量都既有getter,又有setter 自动生成该方法
  var age:Int = 28

  //类私有字段,只能在类的内部使用或者伴生对象中访问
  private val  address:String = "地球上"

  //类私有字段,访问权限更加严格的,该字段在当前类中被访问
  //在伴生对象里面也不可以访问
  private[this] var pet = "小强"

  //在类当中定义了一个方法,
  def hello(first:Int,second:String):Int ={
     
    println(first+"\t"+second)
    250
  }
  /**
   * 定义了一个函数
   */
  val func1 =(x:Int,y:Int) =>{
     
    x+y
  }
}

2.2 类的实例化以及使用

package cn.itcast.scala

object ScalaClass {
     
  def main(args: Array[String]): Unit = {
     
    val person = new Person
    val name: String = person.name
    val age: Int = person.age
    println(name)
    println(age)
    
    person.age = (30) // 这个是赋值操作
    person.age= (30)  // age= 这个是set方法,.age=连起来写
    person.age_= (80) // age_= 这个是set方法
    println(person.age) //这个是get方法
    //调用函数或者方法
    val hello: Int = person.hello(120,"zhangsan")
    println(hello)  //250
  }

}

2.3 属性的getter和setter方法

对于scala类中的每一个属性,编译后,会有一个私有的字段和相应的getter、setter方法生成

//getter方法
println(person age)
//setter方法
println(person age_= (18))
//getter方法
println(person.age)

当然了,你也可以不使用自动生成的方式,自己定义getter和setter方法

class Dog2 {
  private var _leg = 4
  def leg = _leg
  def leg_=(newLeg: Int) {
    _leg = newLeg
  }
}
使用之:
val dog2 = new Dog2
dog2.leg_=(10)
println(dog2.leg)

规范提示:自己手动创建变量的getter和setter方法需要遵循以下原则:

1) 字段属性名以“_”作为前缀,如:_leg
2) getter方法定义为:def leg = _leg
3) setter方法定义时,方法名为属性名去掉前缀,并加上后缀,后缀是:“leg_=”,如例子所示

2.4 类的构造器

scala当中类的构造器分为两种:主构造器和辅助构造器
主构造器,写在类名后面的。
所有的辅助构造器,在最后都必须调用另外一个构造器

java中构造器

public  class Dog{
     
 public Dog(String name,int age){
     
 	System.out.println("xxxx")
 }
}
new Dog("小黑"3)

scala中构造器

package cn.itcast.scala

/**
 * 顶一个class类,主构造器带有两个参数,name与age
 *
 * @param name
 * @param age
 *            scala的执行代码,可以直接将代码写在class当中,而在java当中不能
 *            在Scala编译之后成为.class文件
 *            将我们所有class类的代码都进入到了主构造器方法当中去了
 *            class Dog{
 *              public Dog(String name,int age){
 *                println(name)
 *                println(age)
 *              }
 *            }
 */
class Dog(name: String, age: Int) {
     

  println(name)
  println(age)

  var gender: String = "";

  //使用this关键字来定义我们的构造器
  def this(name: String, age: Int, gender: String) {
     
    //每个辅助构造器,都必须以其他辅助构造器,或者主构造器的调用作为第一句
    this(name: String, age: Int)
    this.gender = gender
  }

  var color = "";

  /**
   * 我们也可以通过private来进行修饰我们的构造器,
   *
   * @param name
   * @param age
   * @param color
   * @param gender
   */
  private def this(name: String, age: Int, color: String, gender: String) {
     
    this(name: String, age: Int)
    this.color = color
  }

}

两个构造器之间不能相互调用
Object通过构造器生成对象

package cn.itcast.scala

object ScalaClass {
     
  def main(args: Array[String]): Unit = {
     
    val xiaoheigou: Dog = new Dog("xiaoheigou",3)
    val xiaobaigou: Dog = new Dog("xiaobaigou",2,"cixing")
  }
}

3.scala当中的对象

Java中

public  class MyClass{

   public static String name="xxx"

   public String age = "xxx"

   public static String getMyAge(){
	return "xxx"
   }

   public int getMyRealAge(){
   
   return 1;
   }
}

Scala中

将static和非static的东西全部分开
object 里面装的东西,可以简单的认为,全部都是static修饰的
class里面装的东西,可以简单的任务,全部都是没有static修饰的(需要new对象)

3.1 scala当中的Object

定义一个class类,然后在class类当中定义一个Object的对象。object对象当中的所有属性或者方法都是静态的

class Session {
     
  def hello(first:Int):Int={
     
    println(first)
    first
  }
}
object SessionFactory{
     
  val session = new Session
  def getSession():Session ={
     
    session
  }
  def main(args: Array[String]): Unit = {
     

    for(x <- 1 to 10){
     
      //通过直接调用,产生的对象都是单列的
      val session = SessionFactory.getSession()
      println(session)
    }
  }
}

3.2 伴生类与伴生对象

25 scala 进阶_第1张图片
特点:

1.如果有一个class文件,还有一个与class同名的object文件,那么就称这个object是class的伴生对象,
class是object的伴生类;
2.伴生类和伴生对象必须存放在一个.scala文件中;
3.伴生类和伴生对象的最大特点是,可以相互访问;
package cn.itcast.scala

class ClassObject {
     
  val id = 1
  private var name = "itcast"
  def printName(): Unit ={
     
    //在Dog类中可以访问伴生对象Dog的私有属性
    println(ClassObject.CONSTANT + name )
  }
}

object ClassObject{
     
  //伴生对象中的私有属性
  private val CONSTANT = "汪汪汪 : "
  def main(args: Array[String]) {
     
    val p = new ClassObject
    //访问私有的字段name
    p.name = "123"
    p.printName()
  }
}

3.3 scala当中的apply方法

通过apply方法来创建我们的伴生类,可以通过伴生对象来创建我们的伴生类,更加简洁和方便

package cn.itcast.scala

//定义一个class类,主构造器传入一个参数
class ApplyClassObject(name:String) {
     
  println(name)

}

object ApplyClassObject{
     
  def apply(name: String): ApplyClassObject = new ApplyClassObject(name)

  def main(args: Array[String]): Unit = {
     
    val applyClassObject1 = new ApplyClassObject("张三")
    //通过伴生对象,直接调用调用apply方法,来获取我们的一个伴生类
    val applyClassObject2 = ApplyClassObject("lisi")

    //底层还是调用了apply方法,apply还是new Array[Int](5)
    val myArray = Array(1,2,3,4,5)
    val  myArray2 = new Array[Int](10)
    myArray2(0)=1
    myArray2(1)=2

  }
}

3.4 scala当中的main方法

//1.在object中定义main方法
object Main_Demo1 {
     
  def main(args: Array[String]) {
     
    if(args.length > 0){
     
      println("Hello, " + args(0))
    }else{
     
      println("Hello World1!")
    }
  }
}
//2.使用继承App Trait ,将需要写在 main 方法中运行的代码
// 直接作为 object 的 constructor 代码即可,
// 而且还可以使用 args 接收传入的参数。

object Main_Demo2 extends App{
     
  if(args.length > 0){
     
    println("Hello, " + args(0))
  }else{
     
    println("Hello World2!")
  }
}

3.5 枚举

java

public enum{
HELLO,ABC,123
}


enum.HELLO

public  static  String CONSTANTS = "HELLO"

Scala中没有枚举类型,但是我们可以通过定义一个扩展Enumeration类的对象,并以value调用初始化枚举中的所有可能值:

4.scala当中的继 承

4.1 Scala中继承(extends)的概念

25 scala 进阶_第2张图片

25 scala 进阶_第3张图片

ackage cn.itcast.extends_demo

class Person {
     
  val name="super"
  def getName=this.name
}
class Student extends Person{
     
  //继承加上关键字
  override
  val name="sub"
  
  //重写方法
  override def getName = "xxx"		
	
  //子类可以定义自己的field和method
  val score="A"
  def getScore=this.score
}

4.2 Scala中override 和 super 关键字

25 scala 进阶_第4张图片

class Person1 {
     
  private val name = "leo"
  val age=50
  def getName = this.name
}
class Student1 extends Person1{
     
  private val score = "A"
  //子类可以覆盖父类的 val field,使用override关键字
  override
  val age=30
  def getScore = this.score
  //覆盖父类非抽象方法,必须要使用 override 关键字
  //同时调用父类的方法,使用super关键字
  override def getName = "your name is " + super.getName
}

4.3 Scala中isInstanceOf 和 asInstanceOf

Class B  extends Class  A
Class C 

 B instanceOf  A   => 如果判断 B是A的子类  (A)B


 C instanceOf  A  ==> 如果判断 C不是A的子类  不能强转

java当中只提供了子类判断是否属于父类形 instanceOf,没有提供判断一个类是否是另外一个类的父类的方法

isInstanceOf 和 asInstanceOf
isInstanceOf    ==>  类似于java当中的instanceOf  做类型判断的
如果  判断 A   isInstanceOf  B  为true
可以调用  A  asInstanceOf  B 做类型转换
asInstanceOf    ==>  做类型转换的

25 scala 进阶_第5张图片

package cn.itcast.extends_demo

class Person3 {
     }
class Student3 extends Person3
object Student3{
     
    def main (args: Array[String] ) {
     
    val p: Person3 = new Student3
    var s: Student3 = null
    //如果对象是 null,则 isInstanceOf 一定返回 false
    println (s.isInstanceOf[Student3])
    // 判断 p 是否为 Student3 对象的实例
  if (p.isInstanceOf[Student3] ) {
     
    //把 p 转换成 Student3 对象的实例
      s = p.asInstanceOf[Student3]
  }
  println (s.isInstanceOf[Student3] )
  }
}

4.4 Scala中getClass 和 classOf

传入一个Any 是不是Array 这一个确定的类型

package cn.itcast.extends_demo

class Person4 {
     }
class Student4 extends Person4
object Student4{
     
  def main(args: Array[String]) {
     
    val p:Person4=new Student4
    //判断p是否为Person4类的实例
    println(p.isInstanceOf[Person4])//true
    //判断p的类型是否为Person4类
    println(p.getClass == classOf[Person4])//false
    //判断p的类型是否为Student4类
    println(p.getClass == classOf[Student4])//true
  }
}

4.5 Scala中使用模式匹配进行类型判断

package cn.itcast.extends_demo

class Person5 {
     }
class Student5 extends Person5
object Student5{
     
  def main(args: Array[String]) {
     
    val p:Person5=new Student5
    p match {
     
      // 匹配是否为Person类或其子类对象
      case per:Person5 => println("This is a Person5's Object!")
      // 匹配所有剩余情况
      case _  =>println("Unknown type!")
    }
  }
}

4.6 Scala中protected (了解)

在这里插入图片描述

package cn.itcast.extends_demo

class Person6{
     
  protected var name:String="tom"
  protected[this] var hobby:String ="game"
  protected def sayBye=println("再见...")
}
class Student6 extends Person6{
     
  //父类使用protected 关键字来修饰 field可以直接访问
  def  sayHello =println("Hello "+name)
  //父类使用protected 关键字来修饰method可以直接访问
  def  sayByeBye=sayBye
  def makeFriends(s:Student6)={
     
    println("My hobby is "+hobby+", your hobby is UnKnown")
  }
}
object Student6{
     
  def main(args: Array[String]) {
     
    val s:Student6=new Student6
    s.sayHello
    s.makeFriends(s)
    s.sayByeBye
  }
}

4.7 Scala中调用父类的constructor

25 scala 进阶_第6张图片

package cn.itcast.extends_demo

class Person7(val name:String,val age:Int){
     
  var score :Double=0.0
  var address:String="beijing"
  def this(name:String,score:Double)={
     
    //每个辅助constructor的第一行都必须调用其他辅助constructor或者主constructor代码
    //主constructor代码
      this(name,30)
      this.score=score
  }
  //其他辅助constructor
  def this(name:String,address:String)={
     
      this(name,100.0)
      this.address=address
  }
}

class Student7(name:String,score:Double) extends Person7("abc",23 ){
     
    var  myaddress = "上海"

  //注意:子类的辅助构造器,只能够调用子类的主构造器,或者子类的辅助构造器
  //不能够调用父类的辅助构造器或者,或者父类的主构造器
    def  this(name:String,myaddress:String){
     
      //this(name,"tianjin")
    this(name,23.0)
    }
}

object  Student7{
     
  def main(args: Array[String]): Unit = {
     
    val zhangsan = new Student7("zhangsan","lisi")
    println(zhangsan)
  }
}

25 scala 进阶_第7张图片

4.8 Scala中抽象类

package cn.itcast.extends_demo

abstract class Person9(val name:String) {
     
  //必须指出返回类型,不然默认返回为Unit
  def sayHello:String
  def sayBye:String
  val age:Int  //变量的初始化
}
class Student9(name:String) extends Person9(name){
      //随便传一个与构造器类型一直的
  //必须指出返回类型,不然默认
  def sayHello: String = "Hello,"+name
  def sayBye: String ="Bye,"+name
  val age: Int = 50 //变量集成后赋值
}
object Student9{
     
  def main(args: Array[String]) {
     
    val s = new Student9("tom")
    println(s.sayHello)
    println(s.sayBye)
  }
}

5.scala当中的特质trait

5.1 将trait作为接口使用

25 scala 进阶_第8张图片
1.将特质当作接口使用

package cn.itcast.triat


trait HelloTrait {
     
  def sayHello(): Unit
}
trait MakeFriendsTrait {
     
  def makeFriends(c: Children): Unit
}
//多重继承 trait
class Children(val name: String) extends HelloTrait with MakeFriendsTrait with Cloneable with Serializable{
     
  def sayHello() =println("Hello, " + this.name)
  def makeFriends(c: Children) = println("Hello, my name is " + this.name + ", your name is " + c.name)
}
object Children{
     
  def main(args: Array[String]) {
     
    val c1=new Children("tom")
    val c2=new Children("jim")
    c1.sayHello()//Hello, tom
    c1.makeFriends(c2)//Hello, my name is tom, your name is jim
  }
}

5.2 在trait中定义具体的方法

2.特质当中的方法如果实现了方法体,在子类当中就不用覆写了,直接可以拿过来调用

package cn.itcast.triat
/**
 * 比如 trait 中可以包含很多子类都通用的方法,例如打印日志或其他工具方法等等。
 * spark就使用trait定义了通用的日志打印方法;
 */
trait Logger {
     
  def log(message: String): Unit = println(message)
}
class PersonForLog(val name: String) extends Logger {
     
  def makeFriends(other: PersonForLog) = {
     
    println("Hello, " + other.name + "! My name is " + this.name + ", I miss you!!")
    this.log("makeFriends method is invoked with parameter PersonForLog[name = " + other.name + "]")
  }
}
object PersonForLog{
     
  def main(args: Array[String]) {
     
    val p1=new PersonForLog("jack")
    val p2=new PersonForLog("rose")
    p1.makeFriends(p2)
    //Hello, rose! My name is jack, I miss you!!
    //makeFriens method is invoked with parameter PersonForLog[name = rose]
  }
}

5.3 在trait中定义具体field

如果trait当中已经定义好了一个字段,且字段赋值了,在子类当中可以直接使用

package cn.itcast.triat

trait PersonForField {
     
  val  age:Int=50
}

//继承 trait 获取的field直接被添加到子类中
class StudentForField(val name: String) extends PersonForField {
     
  def sayHello = println("Hi, I'm " + this.name + ", my  age  is "+ age)
}

object StudentForField{
     
  def main(args: Array[String]) {
     
    val s=new StudentForField("tom")
    s.sayHello
  }
}

5.4 在trait中定义抽象field

如果特制当中的字段没有实现,那么我们必须在子类当中给实现了

trait SayHelloTrait {
     
  //注意,这个字段,没有实现
  val msg:String
  def sayHello(name: String) = println(msg + ", " + name)
}

class PersonForAbstractField(val name: String) extends SayHelloTrait {
     
  //必须覆盖抽象 field
  val msg = "Hello"
  def makeFriends(other: PersonForAbstractField) = {
     
    this.sayHello(other.name)
    println("I'm " + this.name + ", I want to make friends with you!!")
  }
}
object PersonForAbstractField{
     
  def main(args: Array[String]) {
     
    val p1=new PersonForAbstractField("Tom")
    val p2=new PersonForAbstractField("Rose")
    p1.makeFriends(p2)
  }
}

5.5 在实例对象指定混入某个trait

在对象当中混入某个特质—>利于在不改变代码的情况下进行功能扩展

trait LoggedTrait {
     
  // 该方法为实现的具体方法
  def log(msg: String) = {
     }
}
trait MyLogger extends LoggedTrait{
     
  // 覆盖 log() 方法
  override def log(msg: String) = println("log: " + msg)
}

trait MyLogger2 {
     

  def MyNewMethod(name:String) ={
     
    println("hahhaha")
  }

}


class PersonForMixTraitMethod(val name: String) extends LoggedTrait {
     
  def sayHello = {
     
    println("Hi, I'm " + this.name)
    log("sayHello method is invoked!")
  }
}

/*class PersonForMixTraitMethod(val name: String) extends MyLogger {
  def sayHello = {
    println("Hi, I'm " + this.name)
    log("sayHello method is invoked!")
  }
}*/



object PersonForMixTraitMethod{
     
  def main(args: Array[String]) {
     
    val tom= new PersonForMixTraitMethod("Tom").sayHello //结果为:Hi, I'm Tom
    // 使用 with 关键字,指定混入MyLogger trait
    val rose = new PersonForMixTraitMethod("Rose") with MyLogger
    rose.sayHello
    val rose2 = new PersonForMixTraitMethod("Rose") with MyLogger2
    // 结果为:     Hi, I'm Rose
    // 结果为:     log: sayHello method is invoked!
  }
}

5.6 trait 调用链

25 scala 进阶_第9张图片

package cn.itcast.triat

trait HandlerTrait {
     
  def handle(data: String) = {
     println("last one")}
}
trait DataValidHandlerTrait extends HandlerTrait {
     
  override def handle(data: String) = {
     
              println("check data: " + data)
              super.handle(data)
}
}
trait SignatureValidHandlerTrait extends HandlerTrait {
     
  override def handle(data: String) = {
     
          println("check signature: " + data)
          super.handle(data)
  }
}
class PersonForRespLine(val name: String) extends SignatureValidHandlerTrait with DataValidHandlerTrait {
     
  def sayHello = {
     
        println("Hello, " + this.name)
        this.handle(this.name)
  }
}
object PersonForRespLine{
     
  def main(args: Array[String]) {
     
     val p=new PersonForRespLine("tom")
      p.sayHello
      //执行结果:
//    Hello, tom
//    check data: tom
//    check signature: tom
//    last one
  }
}

25 scala 进阶_第10张图片

5.7 混合使用 trait 的具体方法和抽象方法

package cn.itcast.triat

trait ValidTrait {
     
 //抽象方法
  def getName: String     
//具体方法,具体方法的返回值依赖于抽象方法
                        
 def valid: Boolean = {
     "Tom".equals(this.getName)
  }
}
class PersonForValid(val name: String) extends ValidTrait {
     
  def getName: String = this.name
}

object PersonForValid{
     
  def main(args: Array[String]): Unit = {
     
    val person = new PersonForValid("Rose")
    println(person.valid)
  }
}

5.8 trait的构造机制

25 scala 进阶_第11张图片

package cn.itcast.triat

class Person_One {
     
  println("Person's constructor!")
}
trait Logger_One {
     
  println("Logger's constructor!")
}
trait MyLogger_One extends Logger_One {
     
  println("MyLogger's constructor!")
}
trait TimeLogger_One extends Logger_One {
     
  println("TimeLogger's contructor!")
}
class Student_One extends Person_One with MyLogger_One with TimeLogger_One {
     
  println("Student's constructor!")
  }
object exe_one {
     
  def main(args: Array[String]): Unit = {
     
    val student = new Student_One
    //执行结果为:
//      Person's constructor!
//      Logger's constructor!
//      MyLogger's constructor!
//      TimeLogger's contructor!
//      Student's constructor!
  }
}

5.9 trait 继承 class (java中接口不能)

在这里插入图片描述

package cn.itcast.triat

class MyUtil {
     
  def printMsg(msg: String) = println(msg)
}
trait Logger_Two extends MyUtil {
     
  def log(msg: String) = this.printMsg("log: " + msg)
}
class Person_Three(val name: String) extends Logger_Two {
     
    def sayHello {
     
        this.log("Hi, I'm " + this.name)
        this.printMsg("Hello, I'm " + this.name)
  }
}
object Person_Three{
     
  def main(args: Array[String]) {
     
      val p=new Person_Three("Tom")
      p.sayHello
    //执行结果:
//      log: Hi, I'm Tom
//      Hello, I'm Tom
  }
}

5.10 scala当中的特质总结

1、特质可以作为一个接口使用,里面定义的方法没有方法体
2、特质里面的字段Field,如果不实现,就是一个抽象字段,子类一定要实现
3、特质里面定义好的已经实现了的方法,子类可以拿过来直接使用
4、特质里面定义好的field,已经赋值了,子类可以拿过来直接使用
5、在实例对象中混入某个trait,扩展一些功能
6、Trait的调用链 从右往左边调用
7、Trait的构造器  从左往右边进行实例化
8、Trait继承class类

6.模式匹配和样例类

6.1 字符匹配

def main(args: Array[String]): Unit = {
     
  val charStr = '6'
  charStr match {
     
    case '+' => println("匹配上了加号")
    case '-' => println("匹配上了减号")
    case '*' => println("匹配上了乘号")
    case '/' => println("匹配上了除号")
      //注意。所有的模式匹配都必须最终匹配上一个值,如果没有匹配上任何值,就会报错
    case _  => println("都没有匹配上,我是默认值")
  }
}

6.2 匹配字符串

def main(args: Array[String]): Unit = {
     
  val arr = Array("hadoop", "zookeeper", "spark")
  val name = arr(Random.nextInt(arr.length))
  name match {
     
    case "hadoop"    => println("大数据分布式存储和计算框架...")
    case "zookeeper" => println("大数据分布式协调服务框架...")
    case "spark" => println("大数据分布式内存计算框架...")
    case _ => println("我不认识你...")
  }
}

6.3 守卫

模式匹配当中,我们也可以通过条件进行判断

def main(args: Array[String]): Unit = {
     
  var ch = "500"
    var sign = 0
    ch match {
     
      case "+" => sign = 1
      case "-" => sign = 2
      case _ if ch.equals("500") => sign = 3
      case _ => sign = 4
    }
    println(ch + " " + sign)
}

6.4 匹配类型

注意在map当中会存在泛型擦除的情况。注意在进行非数组的类型匹配的时候,类型都会进行擦除

def main(args: Array[String]): Unit = {
     
  //注意泛型擦除,在模式匹配当中的类型匹配中,除了Array类型以外,所有的其他的数据类型都会被擦除掉
  val a = 3
  val obj = if(a == 1) 1
  else if(a == 2) "2"
  else if(a == 3) BigInt(3)
  else if(a == 4) Map("aa" -> 1)
  else if(a == 5) Map(1 -> "aa")
  else if(a == 6) Array(1, 2, 3)
  else if(a == 7) Array("aa", 1)
  else if(a == 8) Array("aa")
  val r1 = obj match {
     
    case x: Int => x
    case s: String => s.toInt
    case BigInt => -1 //不能这么匹配
    case _: BigInt => Int.MaxValue
    case m: Map[String, Int] => "Map[String, Int]类型的Map集合"
    case m: Map[_, _] => "Map集合"
    case a: Array[Int] => "It's an Array[Int]"
    case a: Array[String] => "It's an Array[String]"
    case a: Array[_] => "It's an array of something other than Int"
    case _ => 0
  }
  println(r1 + ", " + r1.getClass.getName)
}

6.5 匹配数组、元组、集合

def main(args: Array[String]): Unit = {
     
  val arr = Array(0, 3, 5)
  arr match {
     
    case Array(0, x, y) => println(x + " " + y)
    case Array(0) => println("only 0")
      //匹配数组以1 开始作为第一个元素
    case Array(1, _*) => 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")
  }
}

6.6 样例类

25 scala 进阶_第12张图片

case class SubmitTask(id:String,name:String)
case class HeartBeat(time:Long)
case object CheckTimeOutTask

object CaseDemo04  {
     

  def main(args: Array[String]): Unit = {
     
    val arr = Array(CheckTimeOutTask, HeartBeat(12333), SubmitTask("0001", "task-0001"))
    val myInt: Int = Random.nextInt(arr.length)
    println(myInt)
    val arrayResult = arr(1)
    arrayResult match {
     
      case CheckTimeOutTask => println("匹配上了CheckTimeOut")
      case SubmitTask(x,y) =>  println(s"$x....$y")
      case HeartBeat(x) => println("心跳时间为 " + x)
    }
  }
}

6.7 偏函数

25 scala 进阶_第13张图片

val func1: PartialFunction[String, Int] = {
     
  case "one" => 1
  case "two" => 2
 // case _ => -1
}

def func2(num: String) : Int = num match {
     
  case "one" => 1
  case "two" => 2
  case _ => -1
}

def main(args: Array[String]) {
     
  println(func1("one"))
  println(func2("one"))
  //如果偏函数当中没有匹配上,那么就会报错,我们可以通过isDefinedAt来进行判断
 // println(func1("three"))
  println(func1.isDefinedAt("three"))
  if(func1.isDefinedAt("three")){
     
    println("hello world")
  }else{
     
    println("world hello")
  }
}

7.scala当中的类型参数(了解)

7.1 scala当中的类的泛型

object Demo8 {
     
  def main(args: Array[String]): Unit = {
     
    val result1 = new MyClass("hello",50)
    val result2 = new MyClass[Any,Any]("zhangsan","Lisi");
  }
}

/**
  * 定义一个class类,接收两个参数,但是两个参数都是泛型,泛型的类型,会根据我们
  * 创建类的实例化对象的时候,动态的传递进行动态的推断
  * @param first
  * @param second
  * @tparam T
  * @tparam B
  */
class  MyClass[T,B](first:T,second:B){
     
  println(first+","+second)
}

7.2 函数的泛型

object methodType{
     
  def getMiddle[T](canshu:T) ={
     
    canshu
  }
  def main(args: Array[String]): Unit = {
     
    // 从参数类型来推断类型
    println(getMiddle(Array("Bob", "had", "a", "little", "brother")).getClass.getTypeName)
    //指定类型,并保存为具体的函数。
    val f = getMiddle[String] _
    println(f("Bob"))
  }
}

7.3 scala当中的上下界之泛型类型的限定

25 scala 进阶_第14张图片
泛型的上界限定(必须是该类的子类)

class Pair1[T <: Comparable[T]](val first: T, val second: T) {
     
  def smaller = if (first.compareTo(second) < 0) first else second
}

object Main1 extends App{
     
  override def main(args: Array[String]): Unit = {
     
    val p = new Pair1("hello", "Brooks")
    println(p.smaller)
  }
}

泛型的下界限定(必须是该类的父类)

class Pair2[T](val first: T, val second: T) {
     
  def replaceFirst[R >: T](newFirst: R) = new Pair2[R](newFirst, second)
  override def toString = "(" + first + "," + second + ")"
}

object Main2 extends App{
     
  override def main(args: Array[String]): Unit = {
     
    val p = new Pair2("Nick", "Alice")
    println(p)
    println(p.replaceFirst("Joke"))
    println(p)
  }
}

7.4 scala当中的视图界定

/**
  * 使用 <%  来实现我们类型的隐式转换
  * @param first
  * @param second
  * @tparam T
  */
class Pair3[T <% Comparable[T]](val first: T, val second: T) {
     
  def smaller = if (first.compareTo(second) < 0) first else second
  override def toString = "(" + first + "," + second + ")"
}

object Main3 extends App {
     
  val p = new Pair3(4, 2)  //RichInt有CompareTo方法
  println(p.smaller)
}

7.5 scala当中的协变,逆变和非变

Java当中,这两个玩意儿没有关系

class Anmial  {}

class Cat  extends  Anmial{}

List[Cat]   List[Anmial]

在 scala当中

List[cat]  extends  List[Anmial]  协变

List[Anmial]  extends  List[Cat]  逆变

List[Cat]  = List[Cat]   非变
package cn.itcast.scala.enhance.covariance

class Super
class Sub extends Super
//协变
class Temp1[+A](title: String)
//逆变
class Temp2[-A](title: String)
//非变
class Temp3[A](title: String)

object Covariance_demo{
     
  def main(args: Array[String]) {
     
    //支持协变 Temp1[Sub]还是Temp1[Super]的子类
    val t1: Temp1[Super] = new Temp1[Sub]("hello scala!!!")
    //支持逆变 Temp1[Super]是Temp1[Sub]的子类
    val t2: Temp2[Sub] = new Temp2[Super]("hello scala!!!")
    //支持非变 Temp3[Super]与Temp3[Sub]没有从属关系,如下代码会报错
    //val t3: Temp3[Sub] = new Temp3[Super]("hello scala!!!")
//val t4: Temp3[Super] = new Temp3[Sub]("hello scala!!!")
    println(t1.toString)
    println(t2.toString)
  }
}

8.scala当中的Actor并发编程

8.1 scala当中的Actor介绍

25 scala 进阶_第15张图片
25 scala 进阶_第16张图片

25 scala 进阶_第17张图片
25 scala 进阶_第18张图片

8.2 Actor实战

25 scala 进阶_第19张图片
怎么实现actor并发编程:

1、定义一个class或者是object继承Actor特质,注意导包import scala.actors.Actor
2、重写对应的act方法
3、调用Actor的start方法执行Actor
4、当act方法执行完成,整个程序运行结束

第一个例子

package cn.itcast.scala_actor
import scala.actors.Actor

class Actor1 extends Actor{
     
  override def act(): Unit = {
     
    for (x <- 1 to 10){
     
      println(x)
    }
  }
}

object Actor2 extends Actor{
     
  override def act(): Unit = {
     
    for (j <- 1 to 10){
     
      println("j"+j)
    }
  }
}

object Actor1{
     
  def main(args: Array[String]): Unit = {
     
    val actor: Actor1 = new Actor1
    actor.act()
    Actor2.act()
  }
}

第二个例子 实现发送,接收消息

25 scala 进阶_第20张图片

package cn.itcast.scala_actor

import scala.actors.Actor

class MyActor2 extends Actor{
     
  //通过act方法当中,使用receive来进行消息接收
  override def act(): Unit = {
     
    receive{
     
      case "start" => println("start.....")
    }
  }
}

object MyActor2{
     
  def main(args: Array[String]): Unit = {
     
    val actor = new MyActor2
    //启动我们的actor,类似我们启动线程
    actor.start()
    //发送一个异步没有返回值的消息
    actor ! "xxx"
    actor ! "start"
  }
}

第三个例子 实现actor可以不断地接受消息

怎么实现actor可以不断地接受消息
在act方法中可以使用while(true)的方式,不断的接受消息。

class MyActor3 extends  Actor{
     
  override def act(): Unit = {
     
    while (true){
     
      receive{
     	//每次来一条消息都会启动一个线程去执行,线程开销太大
        case  "start" => println("starting")
        case "stop" =>println("stopping")
      }
    }
  }
}
object MyActor3{
     
  def main(args: Array[String]): Unit = {
     
    val actor = new MyActor3
    actor.start()
    actor ! "start"
    actor ! "stop"
  }
}

第四个例子 使用react方法代替receive方法去接受消息

使用react方法代替receive方法去接受消息
好处:react方式会复用线程,避免频繁的线程创建、销毁和切换。比receive更高效
注意: react 如果要反复执行消息处理,react外层要用loop,不能用while

class MyActor4 extends Actor{
     
  override def act(): Unit = {
     
    loop{
     
      react{
     
        case "start" => println("starting")
        case "stop" => println("stopping")
      }
    }
  }
}


object MyActor4{
     
  def main(args: Array[String]): Unit = {
     
    val actor = new MyActor4
    actor.start()
    actor ! "start"
    actor ! "stop"

  }
}

第五个例子 结合case class样例类发送消息和接受消息

结合case class样例类发送消息和接受消息

1、将消息封装在一个样例类中
2、通过匹配不同的样例类去执行不同的操作
Actor可以返回消息给发送方。通过sender方法向当前消息发送方返回消息
//异步消息
case class AsyncMessage(id:Int,message:String)
//同步消息
case class SyncMessage(id:Int,message:String)
//返回消息
case class ReplyMessage(id:Int,message:String)
class MyActor5 extends Actor{
     
  override def act(): Unit = {
     
    loop{
     
      react{
     
        case AsyncMessage(id,message) => {
     
          println(s"$id,$message")
          sender ! ReplyMessage(2,"异步有返回值的消息处理成功")
        }
        case SyncMessage(id,message) =>{
     
          println(s"$id,$message")
          sender ! ReplyMessage(id,"我是同步消息的返回值,等到我返回之后才能继续下一步的处理")
        }
      }
    }
  }
}

object  MyActor5{
     

  def main(args: Array[String]): Unit = {
     
    val actor: MyActor5 = new MyActor5
    actor.start()
    //发送异步无返回值消息
    actor ! AsyncMessage(1,"我是一个异步无返回值的消息不要回答")
    //发送异步有返回值消息
    val asyncMessage: Future[Any] = actor !! AsyncMessage(2,"actorSend")
    val apply: Any = asyncMessage.apply()
    println(apply)
    println("helloworld22222")
    //同步等待返回值消息
    val syncMessage: Any = actor !? SyncMessage(3,"我是同步阻塞消息")
    println(syncMessage)
  }
}

练习实战 用actor并发编程写一个单机版的WordCount

25 scala 进阶_第21张图片
25 scala 进阶_第22张图片

package cn.itcast.scala_actor

import scala.actors.{
     Actor, Future}
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.io.{
     BufferedSource, Source}

case class FilePath(fileNamePath:String)

case class ReplyWord(returnMap:Map[String,Int])

class WordCountActor extends Actor{
     
  override def act(): Unit = {
     
    //loop react不断接收数据
    loop{
     
      react{
     
        case FilePath(fileNamePath) =>{
     
          //获取到文件路径之后,读取文件内容
          val fileContent: BufferedSource = Source.fromFile(fileNamePath)
          //获取文件流中所用内容
          val fileContentStr: String = fileContent.mkString
          println(fileContentStr)
          //文件内容按照换行符切分
          // win-\r\n linux-\r mac-\n
          val split: Array[String] = fileContentStr.split("\r\n")
          /*
          方法1:
          //将Array中每个元素取出来,按照空格切
          val map: Array[Array[String]] = split.map(x => x.split(" "))
          //Array(Array(hello world hadoop hive),Array(sqoop hadoop hello world))
          println(map.toBuffer)
          val flatten: Array[String] = map.flatten  //压平
          println(flatten.toBuffer)
          //ArrayBuffer(hello, world, hadoop, hive, sqoop, hadoop, hello, world)

          //给每一个单词记做1 hello  1   world  1  hadoop 1  hello 1
          //然后再给每一个单词进行分组   hello  (1,1)
          */
          // 方法2:
          val words: Array[String] = split.flatMap(x => x.split(" "))
          println(words.toBuffer)
          //如何将每个Array中的每个元素取出来,编程如下形式
          //Array((hello,1),(hadoop,1))
          //ArrayBuffer((hello,1), (world,1), (hadoop,1), (hive,1), (sqoop,1), (hadoop,1), (hello,1), (world,1))
          val wordAndOne: Array[(String, Int)] = words.map(x => (x,1))
          println(wordAndOne.toBuffer)
          //将Array中每个元素,取出来,作用再groupBy上面
          val by: Map[String, Array[(String, Int)]] = wordAndOne.groupBy(x => x._1)
          for ((k,v) <- by){
     
            println(k)
            println(v.toBuffer)
          }
          /*
            world
            ArrayBuffer((world,1), (world,1))
            sqoop
            ArrayBuffer((sqoop,1))
            hadoop
            ArrayBuffer((hadoop,1), (hadoop,1))
            hive
            ArrayBuffer((hive,1))
            hello
            ArrayBuffer((hello,1), (hello,1))
           */
          //获取每个map中每一个value的长度,就是我们单词出现的次数
          //将map当中每一个value取出来,作用在下面这个函数,然后返回新的map
          //新map的key还是原来的key,value改变
          val values: Map[String, Int] = by.mapValues(x => x.length)
          /*
          for ((x,y) <- values){
            println(x,y)
          }
          ArrayBuffer((hello,1), (hello,1))
                      (world,2)
                      (sqoop,1)
                      (hadoop,2)
                      (hive,1)
                      (hello,2)

           */
          //将我们得到的每个文件结果返回
          sender ! ReplyWord(values)
        }
      }
    }
  }
}

object WordCountActor{
     
  def main(args: Array[String]): Unit = {
     
    //一个文件
    val filePath = "E:\\大数据资料\\大数据实时资料\\4、Scala\\2、Scala第二天\\wordCount\\1.txt"
    //多个文件
    val files = Array("E:\\大数据资料\\大数据实时资料\\4、Scala\\2、Scala第二天\\wordCount\\1.txt","E:\\大数据资料\\大数据实时资料\\4、Scala\\2、Scala第二天\\wordCount\\2.txt","E:\\大数据资料\\大数据实时资料\\4、Scala\\2、Scala第二天\\wordCount\\3.txt")
    val mySet: mutable.HashSet[Future[Any]] = new mutable.HashSet[Future[Any]]()
    val replyWords: ListBuffer[ReplyWord] = new ListBuffer[ReplyWord]
    
    for (f <- files){
     
      val actor = new WordCountActor
      actor.start()
      //获取到异步发送的返回值
      val value: Future[Any] = actor !! FilePath(f)
      mySet.add(value)
    }
    while (mySet.size>0){
     
      //一定要过滤掉我们set集合中没有数据的可能性
      val filter: mutable.HashSet[Future[Any]] = mySet.filter(x => x.isSet)
      for (eachFuture <- filter){
     
          val apply: Any = eachFuture.apply()
          val word: ReplyWord = apply.asInstanceOf[ReplyWord]
          //将真正的值转换成样例类,再加入到ListBuffer里去
          replyWords.+=(word)
          //避免死循环不退出
          mySet.remove(eachFuture)
      }
    }
    val map: ListBuffer[Map[String, Int]] = replyWords.map(x => x.returnMap)
    /*
      println(map)
      ListBuffer(Map(world -> 2, sqoop -> 1, hadoop -> 2, hive -> 1, hello -> 2), Map(world -> 2, sqoop -> 1, hadoop -> 2, hive -> 1, hello -> 2), Map(world -> 2, sqoop -> 1, hadoop -> 2, hive -> 1, hello -> 2))
     */
    /*map.map(x=>println(x.toBuffer))
      ArrayBuffer((world,2), (sqoop,1), (hadoop,2), (hive,1), (hello,2))
      ArrayBuffer((world,2), (sqoop,1), (hadoop,2), (hive,1), (hello,2))
      ArrayBuffer((world,2), (sqoop,1), (hadoop,2), (hive,1), (hello,2))
     */
    val flatten: ListBuffer[(String, Int)] = replyWords.map(x => x.returnMap).flatten
    /*
      println(flatten)
      ListBuffer((world,2), (sqoop,1), (hadoop,2), (hive,1), (hello,2), (world,2), (sqoop,1), (hadoop,2), (hive,1), (hello,2), (world,2), (sqoop,1), (hadoop,2), (hive,1), (hello,2))
     */
      //按照k进行分组
    val by: Map[String, ListBuffer[(String, Int)]] = flatten.groupBy(x => x._1)
      /*
      for ((x,y) <- by){
        println(x,y)
      }
      (world,ListBuffer((world,2), (world,2), (world,2)))
      (sqoop,ListBuffer((sqoop,1), (sqoop,1), (sqoop,1)))
      (hadoop,ListBuffer((hadoop,2), (hadoop,2), (hadoop,2)))
      (hive,ListBuffer((hive,1), (hive,1), (hive,1)))
      (hello,ListBuffer((hello,2), (hello,2), (hello,2)))
       */
    //每个value都是ListBuffer,将每个
    val values: Map[String, Int] = by.mapValues(x => x.foldLeft(0)(_ + _._2))
//    by.mapValues(x => x.foldLeft(0)((x,y) => x + y._2))
    //(0)((x,y)) => x = 0 + 2 => 2+2 => 4+2
    for ((x,y) <- values){
     
      println(x,y)
    }
  }
}

9.scala当中的文件操作和网络请求

9.1 读取文件当中每一行的数据

package cn.itcast.scala_actor

import scala.io.{
     BufferedSource, Source}

object Test {
     
  def main(args: Array[String]): Unit = {
     
    val file: BufferedSource = Source.fromFile("E:\\大数据资料\\大数据实时资料\\4、Scala\\3、Scala第三天\\files\\file.txt","GBK")
    val lines: Iterator[String] = file.getLines()
    //法1
    for(line <- lines){
     
      println(line)
    }
    println("===========")
    //法2
    while(lines.hasNext){
     
      println(lines.next())
    }
    //注意关闭文件
    file.close()
  }
}

如果要将文件内容转数组,直接调用toArray即可

9.2 读取词法单元和数字

如果想将以某个字符或某个正则表达式分开的字符成组读取,可以这么做:

def main(args: Array[String]): Unit = {
     
  val file: BufferedSource = Source.fromFile("F:\\scala与spark课件资料教案\\3、scala第三天\\files\\file2.txt","GBK");
  val split: Array[String] = file.mkString.split(" ")
  println(split.mkString("\t"))
  file.close()
}

9.3 读取网络资源、文件写入、控制台操作

1、读取网络资源

def main(args: Array[String]): Unit = {
     
  val source: BufferedSource = Source.fromURL("http://www.baidu.com")
  val string: String = source.mkString

  println(string)
  source.close()
}

2、文件写入操作

def main(args: Array[String]): Unit = {
     
  val writer = new PrintWriter("E:\\大数据资料\\大数据实时资料\\4、Scala\\3、Scala第三天\\filesprintWriterx.txt")
  for(i <- 1 to 100){
     
    writer.println(i)
    writer.flush()
  }
  writer.close()
}

3、控制台交互操作

def main(args: Array[String]): Unit = {
     
  //控制台交互--老API
  print("请输入内容:")
  val consoleLine1 = Console.readLine()
  println("刚才输入的内容是:" + consoleLine1)

  //控制台交互--新API
  print("请输入内容(新API):")
  val consoleLine2 = StdIn.readLine()
  println("刚才输入的内容是:" + consoleLine2)
}

9.4 scala当中的序列化

@SerialVersionUID(1L)
class Person extends Serializable{
     
  override def toString = name + "," + age

  val name = "Nick"
  val age = 20

}

object PersonMain extends App{
     
  override def main(args: Array[String]): Unit = {
     

    import java.io.{
     FileOutputStream, FileInputStream, ObjectOutputStream, ObjectInputStream}
    val nick = new Person
    val out = new ObjectOutputStream(new FileOutputStream("Nick.obj"))
    out.writeObject(nick)
    out.close()

    val in = new ObjectInputStream(new FileInputStream("Nick.obj"))
    val saveNick = in.readObject()
    in.close()
    println(saveNick)
  }
}

9.5 scala当中的正则表达式

我们可以通过正则表达式匹配一个句子中所有符合匹配的内容,并输出:

object Test extends App{
     
  override def main(args: Array[String]): Unit = {
     
      import scala.util.matching.Regex
      val pattern1 = new Regex("(S|s)cala")
      val pattern2 = "(S|s)cala".r
      val str = "Scala is scalable and cool"
      println((pattern2 findAllIn str).mkString(","))
      println((pattern1 findAllIn str).mkString(","))
}}

10.隐式转换和隐式参数

10.1 隐式转换

25 scala 进阶_第23张图片

10.2 隐式参数

25 scala 进阶_第24张图片

10.3 隐式转换作用域与时机

25 scala 进阶_第25张图片

10.4 隐式转换和隐式参数案例

隐式转换案例一(将我们的Double类型的数据自动转换成Int类型)

object Chapter14 {
     
  implicit def ConvertDoubleToInt(first:Double):Int= first.toInt
}

object Convert{
     
  //导入隐式转换的方法
  import Chapter14._
  def main(args: Array[String]): Unit = {
     
    val first:Int = 3.5
    println(first)  //3
  }
}

例如我们也可以定义猫和狗,并且让狗学会抓老鼠的技能

object CatAndDog {
     
  implicit  def dogCatchMouse(dog:Dog) = new Cat()
  def main(args: Array[String]): Unit = {
     
      val dog = new Dog
      dog.catMouse("大黄狗")
  }
}
class Cat{
     
  def catMouse(name:String): Unit ={
     
    println(name+"catch a mouse")
  }
}
class Dog{
     
  def wangwangwang(name:String) ={
     
    println(name+"看门汪汪汪")
  }
}

隐式转换案例二(让File类具备RichFile类中的read方法)

import java.io.File
import scala.io.Source
object MyPredef{
     
  //定义隐式转换方法
  implicit def file2RichFile(file: File)=new RichFile(file)
}
class RichFile(val f:File) {
     
  def read()=Source.fromFile(f,"GBK").mkString
}
object RichFile{
     
  def main(args: Array[String]) {
     
    val f=new File("F:\\scala与spark课件资料教案\\3、scala第三天\\files\\file.txt")
    //使用import导入隐式转换方法
    import MyPredef._
    //通过隐式转换,让File类具备了RichFile类中的方法
    val content=f.read()
    println(content)
  }
}

隐式转换案例三(超人变身)

class Man(val name:String)
class SuperMan(val name: String) {
     
  def heat=print("超人打怪兽")
}
object SuperMan{
     
  //隐式转换方法
  implicit def man2SuperMan(man:Man)=new SuperMan(man.name)
  def main(args: Array[String]) {
     
    val hero=new Man("hero")
    //Man具备了SuperMan的方法
    hero.heat
  }
}

隐式转换案例四(一个类隐式转换成具有相同方法的多个类)

class A(c:C) {
     
  def readBook(): Unit ={
     
    println("A说:好书好书...")
  }
}
class B(c:C){
     
  def readBook(): Unit ={
     
    println("B说:看不懂...")
  }
  def writeBook(): Unit ={
     
    println("B说:不会写...")
  }
}
class C
object AB{
     
  //创建一个类的2个类的隐式转换
  implicit def C2A(c:C)=new A(c)
  implicit def C2B(c:C)=new B(c)
}
object B{
     
  def main(args: Array[String]) {
     
    //导包
    //1. import AB._ 会将AB类下的所有隐式转换导进来
    //2. import AB._C2A 只导入C类到A类的的隐式转换方法
    //3. import AB._C2B 只导入C类到B类的的隐式转换方法
    import AB._
    val c=new C
    //由于A类与B类中都有readBook(),只能导入其中一个,否则调用共同方法时代码报错
    //c.readBook()
    //C类可以执行B类中的writeBook()
    c.writeBook()
  }
}

隐式参数案例五(员工领取薪水)

object Company{
     
  //在object中定义隐式值    注意:同一类型的隐式值只允许出现一次,否则会报错
  implicit  val aaa="zhangsan"
  implicit  val bbb=10000.00
}
class Boss {
     
  //注意参数匹配的类型   它需要的是String类型的隐式值
  def callName()(implicit name:String):String={
     
    name+" is coming !"
  }
  //定义一个用implicit修饰的参数
  //注意参数匹配的类型    它需要的是Double类型的隐式值
  def getMoney()(implicit money:Double):String={
     
    " 当月薪水:"+money
  }
}
object Boss extends App{
     
  //使用import导入定义好的隐式值,注意:必须先加载否则会报错
  import Company._
  val boss =new Boss
  println(boss.callName()+boss.getMoney())
}

11.scala编程实战

11.1 使用Akka实现一个简易版的spark通信框架

25 scala 进阶_第26张图片

11.2 项目概述

25 scala 进阶_第27张图片
25 scala 进阶_第28张图片
25 scala 进阶_第29张图片
25 scala 进阶_第30张图片

11.3 项目实现

25 scala 进阶_第31张图片

实战一 利用Akka的actor编程模型,实现2个进程间的通信。

架构图

25 scala 进阶_第32张图片

重要类介绍

25 scala 进阶_第33张图片

Actor

25 scala 进阶_第34张图片

具体代码
第一步:创建maven工程,导入jar包
	
        
            org.scala-lang</groupId>
            scala-library</artifactId>
            ${
     scala.version}</version>
        </dependency>

        
            com.typesafe.akka</groupId>
            akka-actor_2.11</artifactId>
            2.3.14</version>
        </dependency>

        
            com.typesafe.akka</groupId>
            akka-remote_2.11</artifactId>
            2.3.14</version>
        </dependency>

    </dependencies>

    
        src/main/scala</sourceDirectory>
        src/test/scala</testSourceDirectory>
        
            <!-- 限制jdk的编译版本插件 -->
            
                org.apache.maven.plugins</groupId>
                maven-compiler-plugin</artifactId>
                3.0</version>
                
                    1.8</source>
                    1.8</target>
                    UTF-8</encoding>
                </configuration>
            </plugin>

            <!--编译Scala代码必须要用到的一个包-->
            
                net.alchim31.maven</groupId>
                scala-maven-plugin</artifactId>
                3.2.2</version>
                
                    
                        
                            compile</goal>
                            testCompile</goal>
                        </goals>
                        
                            
                                -dependencyfile</arg>
                                ${
     project.build.directory}/.scala_dependencies</arg>
                            </args>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- 打包时候的插件,将我们其他一些依赖的jar包全部打包到一起去 -->
            
                org.apache.maven.plugins</groupId>
                maven-shade-plugin</artifactId>
                2.4.3</version>
                
                    
                        package</phase>
                        
                            shade</goal>
                        </goals>
                        
                            
                                <filter>
                                    *:*</artifact>
                                    
                                        META-INF/*.SF</exclude>
                                        META-INF/*.DSA</exclude>
                                        META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                            
                                "org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                    reference.conf</resource>
                                </transformer>
                                "org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    </mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
第二步:master进程代码开发
package cn.itcast.scala_akka

import akka.actor.{
     Actor, ActorRef, ActorSystem, Props}
import com.typesafe.config.{
     Config, ConfigFactory}

class Master extends Actor{
     
  //这个receive方法会反复不断的被调用,一旦有消息就会收得到
  //类似loop{react{}}
  println("我是构造器,最先调用")

  override def preStart(): Unit = {
     
    println("我是初始化的方法,master对象创建完成后就会调用")
  }

  override def receive: Receive = {
     
    case "connect" => {
     
      println("a client connected")
      sender ! "success"
    }


  }
}

object Master{
     
  def main(args: Array[String]): Unit = {
     
    val host = "127.0.0.1"
    val port = 8888
    val configStr:String =
      s"""
        |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
        |akka.remote.netty.tcp.hostname = "$host"
        |akka.remote.netty.tcp.port = "$port"
      """.stripMargin
    val config: Config = ConfigFactory.parseString(configStr)
    //获取我们的ActorSystem,通过ActorSystem实现获取一个actor
    val actorSystem = ActorSystem("actorSystem",config)
    //创建master的actor,并且给master的actor起一个名字叫做master
    //props里面需要传入一个actor的子类
    val master: ActorRef = actorSystem.actorOf(Props(new Master),"master")
    //不需要调用start直接发


  }
}
第三步:worker进程代码开发
package cn.itcast.scala_akka

import akka.actor.{
     Actor, ActorRef, ActorSelection, ActorSystem, Props}
import com.typesafe.config.{
     Config, ConfigFactory}

class Worker extends Actor{
     

  override def preStart(): Unit = {
     
    println("我是初始化调用的方法")
    //在这里实现worker给master发送消息
    //通过context上下文对象,使用actorSelection方法,向指定的actor发送数据
    //注意:akka.tcp://[email protected]:8888 是我们ActorSystem
    //通过ActorSystem创建了一个子actor 名字叫做master 通过/user/master对应我们的actor
    val master: ActorSelection = context.actorSelection("akka.tcp://[email protected]:8888/user/master")
    master ! "connect"
  }

  override def receive: Receive = {
     
    case "connect" => println("a client connected ")
    case "success" => println("successful")
  }
}

object Worker{
     
  def main(args: Array[String]): Unit = {
     
    val host = "127.0.0.1"
    val port = 6666
    val configStr:String =
      s"""
         |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
         |akka.remote.netty.tcp.hostname = "$host"
         |akka.remote.netty.tcp.port = "$port"
      """.stripMargin
    val config: Config = ConfigFactory.parseString(configStr)
    //获取我们的ActorSystem,通过ActorSystem实现获取一个actor
    val actorSystem = ActorSystem("actorSystem",config)
    val worker: ActorRef = actorSystem.actorOf(Props(new Worker),"worker")

  }
}

实战二 使用Akka实现一个简易版的spark通信框架

架构图

25 scala 进阶_第35张图片

具体代码
① Master类
package cn.itcast.scala_spark

import akka.actor.{
     Actor, ActorRef, ActorSystem, Props}
import cn.itcast.scala_spark.util.{
     RegisterMessage, RegisteredMessage, SendHeartBeat, WorkerInfo}
import com.typesafe.config.{
     Config, ConfigFactory}

import scala.collection.mutable

class SparkMaster extends Actor{
     
  println("master构造器")

  override def preStart(): Unit = {
     

  }

  //将我们worker注册信息封装到Map里面去,map的key就是我们的workid,map的value就是我们的WorkerInfo对象
  private val workMsgMap = new mutable.HashMap[String,WorkerInfo]()

  override def receive: Receive = {
     
    case RegisterMessage(workerId,memory,cores) => {
     
      //得到了worker注册信息,并保存到Map里去
      val workerInfo = new WorkerInfo(workerId,memory,cores)
      workMsgMap.put(workerId,workerInfo)
      //保存好注册成功信息后,master向worker反馈一下注册成功信息
      sender ! RegisteredMessage("恭喜你注册成功!")
    }
    case SendHeartBeat(workerId) => {
     
      //获取到了心跳信息
      println("接收心跳信息的workId为" + workerId)
      //判断我们保存的注册信息是否在map当中存在
      if(workMsgMap.contains(workerId)){
     
        val workerInfo: WorkerInfo = workMsgMap(workerId)
        //更新我们的心跳时间
        workerInfo.lastHeartBeatTime = System.currentTimeMillis()
      }
    }
  }
}


object SparkMaster{
     
  def main(args: Array[String]): Unit = {
     
    val host = "127.0.0.1"
    val port = 8888
    val configStr:String =
      s"""
         |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
         |akka.remote.netty.tcp.hostname = "$host"
         |akka.remote.netty.tcp.port = "$port"
      """.stripMargin
    val config: Config = ConfigFactory.parseString(configStr)
    val masterActorSystem = ActorSystem("masterActorSystem",config)
    val sparkMaster: ActorRef = masterActorSystem.actorOf(Props(new SparkMaster),"sparkMaster")

  }
}
② Worker类
package cn.itcast.scala_spark

import java.util.UUID

import akka.actor.{
     Actor, ActorRef, ActorSelection, ActorSystem, Props}
import cn.itcast.scala_spark.util.{
     HeartBeat, RegisterMessage, RegisteredMessage, SendHeartBeat}
import com.typesafe.config.{
     Config, ConfigFactory}

import scala.concurrent.duration._

class SparkWorker extends Actor{
     

  println("worker构造器调用")
  private val workId: String = UUID.randomUUID().toString
  private val memory: Int = 128
  private val cores: Int =16

//将我们master的引用提到全局变量,外部都可以使用
  var selection: ActorSelection = _

  override def preStart(): Unit = {
     
      println("前置执行方法")
    //worker向master发送注册信息
    //获取sparkMaster的actor的引用
    selection= context.actorSelection("akka.tcp://[email protected]:8888/user/sparkMaster")
    selection ! RegisterMessage(workId,memory,cores)
  }
  override def receive: Receive = {
     
    //将master反馈的信息打印出来
    case RegisteredMessage(msg) => {
     
      println(msg)
      //继续调用定时模块,定时向master发送心跳信息
      /*
      initialDelay
      interval
      receiver  这里没有办法直接向sparkMaster发送数据,只能向自己发送数据
      message
       */
      import context.dispatcher
      context.system.scheduler.schedule(0 millis,10000 millis,self,HeartBeat)

    }
    case HeartBeat =>{
     
      //如果收到自己的心跳,向sparkMaster发送心跳
      println("准备发送心跳信息")
      //sender ! SendHeartBeat(workId)
      selection ! SendHeartBeat(workId)
    }
  }


}

object SparkWorker{
     
  def main(args: Array[String]): Unit = {
     
    val host = "127.0.0.1"
    val port = 6666
    val configStr:String =
      s"""
         |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
         |akka.remote.netty.tcp.hostname = "$host"
         |akka.remote.netty.tcp.port = "$port"
      """.stripMargin
    val config: Config = ConfigFactory.parseString(configStr)
    val workerActorSystem = ActorSystem("workerActorSystem",config)
    val sparkWorder: ActorRef = workerActorSystem.actorOf(Props(new SparkWorker),"sparkWorder")

  }
}
③ WorkerInfo类
package cn.itcast.scala_spark.util

//封装worker信息
class WorkerInfo(val workerId:String,val memory:Int,val cores:Int) {
     
  //定义一个变量用于存放worker上一次心跳时间
  var lastHeartBeatTime:Long=_  //占位符

  override def toString: String = {
     
    s"workerId:$workerId , memory:$memory , cores:$cores"
  }
}
④ 样例类
package cn.itcast.scala_spark.util

trait RemoteMessage  extends Serializable{
     
}
//worker向master发送注册信息,由于不在同一进程中,需要实现序列化
case class RegisterMessage(val workerId:String,val memory:Int,val cores:Int) extends RemoteMessage
//master反馈注册成功信息给worker,由于不在同一进程中,也需要实现序列化
case class RegisteredMessage(message:String) extends RemoteMessage
//worker向worker发送心跳 由于在同一进程中,不需要实现序列化
case object HeartBeat
//worker向master发送心跳,由于不在同一进程中,需要实现序列化
case class SendHeartBeat(val workerId:String) extends RemoteMessage
//master自己向自己发送消息,由于在同一进程中,不需要实现序列化
case object CheckOutTime

你可能感兴趣的:(scala)