scala03

1. 样例类

  样例类是一种特殊的类,它可以用来快速定义一个保存数据的类,类似于java中的pojo类。

  • 如果要实现成员变量可以被修改需要添加var
  • 默认是val,可以省略
object Demo01 {

  //变量的默认修饰符不写就是:val
  case class Person(name: String, var age: Int)

  def main(args: Array[String]): Unit = {
    //样例对象不用new,说明重写了apply
    val p = Person("刘德华", 54)
    //重写了toString方法
    println(p)
    //验证样例类的默认修饰符是val
    //p.age=24
    println("_" * 30)
    //演示样例类额equals方法,因为样例类的底层已经重写了


    val p1 = Person("周星驰", 46)
    val p2 = Person("周星驰", 46)
    println(p1 == p2) //true比较的是属性值
    println(p1.eq(p2)) //false比较的是地址值

    println("_" * 30)

    //演示样例类对象的hash值
    //相同对象hash肯定相同,不同对象的hash一般不同,但是可能相同。
    println(p1.hashCode())
    println(p2.hashCode())
    println("_" * 30)
    //补充内容,内容不同,但是hash值相同的特例
    println("重地".hashCode)
    println("通话".hashCode)
    println("_" * 30)

    println("儿女".hashCode)
    println("农丰".hashCode)
    println("_" * 30)

    //测试copy方法
    val p3 = Person("陈一发", 27)
    p3.copy("刘一发", 26) //copy相当重新new了一个对象

  }

}
View Code

2. 样例对象

  使用case object可以创建样例对象,样例对象是单例的,而且他没有主构造器

trait Sex /*定义一个性别特质*/
case object Male extends Sex        // 定义一个样例对象并实现了Sex特质
case object Female extends Sex        

case class Person(name:String, sex:Sex)

object CaseClassDemo {
  def main(args: Array[String]): Unit = {
    val zhangsan = Person("张三", Male)

    println(zhangsan)
  }
}
View Code

3. 模式匹配

A:简单模式匹配

package com.itheima.moshipipei

import scala.io.StdIn

//模式匹配之简单匹配
object Demo01 {

  def main(args: Array[String]): Unit = {
    //录入字符串并接收
    print("请输入字符串")
    var str = StdIn.readLine()


    //判断字符串是否是指定结果,并接收结果
    val result: String = str match {
      case "hadoop" => "大数据分布式存储和计算框架"
      case "zookeeper" => "大数据分布式协调服务框架"
      case "spark" => "大数据分布式计算框架"
      case _ => "未匹配"
    }
    //打印结果
    println(result)

    println("-" * 30)

    str match {
      case "hadoop" => println("大数据分布式存储和计算框架")
      case "zookeeper" => println("大数据分布式协调服务框架")
      case "spark" => println("大数据分布式计算框架")
      case _ => println("未匹配")
    }


  }

}
View Code

B:匹配类型

package com.itheima.moshipipei

//模式匹配之匹配类型
object Demo02 {

  def main(args: Array[String]): Unit = {

    val a:Any="hadoop"

    val b:Any=1.0

    a match {
      case x:String =>println(s"${x}是String类型数据")
      case x:Double =>println(s"${x}是Double类型数据")
      case x:Int =>println(s"${x}是Int类型数据")
      case _=> println("未匹配")
    }

    println("-"*30)

    //如果case在校验的时候,没有被使用,则可以用_替代
    b match {
      case _:String =>println("String")
      case _:Double =>println("Double")
      case _:Int =>println("Int")
      case _=> println("未匹配")
    }


  }

}
View Code

C:守卫

package com.itheima.moshipipei

import scala.io.StdIn

object Demo03 {

  def main(args: Array[String]): Unit = {
    println("请录入一个整数:")
    var num=StdIn.readInt()

    num match {
      case a if a>0 && a<=3  =>println("a[0-3]")
      case a if a>=4 && a<=8  =>println("a[4-8]")
      case _=>println("未匹配")
    }
  }

}
View Code

D:匹配样例类

package com.itheima.moshipipei

//匹配样例类
//注意:通过match进行匹配的时候,要匹配的对象必须声明成any类型
object Demo06 {

  case class Customer(var name: String, var age: Int)

  case class Order(id: Int)


  def main(args: Array[String]): Unit = {


    val c: Any = Customer("刘德华", 73)
    val o: Any = Order(123)

    c match {
      case Customer(x, y) => println(s"Customer:${x},${y}")
      case Order(x) => println("Order")
      case _ => println("未匹配")
    }

  }

}
View Code

E:匹配数组

package com.itheima.moshipipei

object Demo04 {

  def main(args: Array[String]): Unit = {
    //定义三个数组
    val arr1 = Array(1, 2, 3)

    val arr2 = Array(0)

    val arr3 = Array(0, 1, 2, 3, 4, 5)

    //通过模式匹配找到合适的数组

    arr1 match {
      //长度为3,首元素为1,后两位无所谓
      case Array(1, x, y) => println(s"匹配长度为3,首元素是1,后二${x},${y}")
      //匹配只有一个0元素的数组
      case Array(0) => println("只有一个元素0")
      //匹配第一个元素是1,后面元素无所谓
      case Array(1, _*) => println("第一个元素是1,后面元素无所谓")
      //其他校验
      case _ => println("未匹配")
    }
  }

}
View Code

F:匹配列表

package com.itheima.moshipipei

object Demo05 {


  def main(args: Array[String]): Unit = {
    val list1 = List(0)
    val list2 = List(0, 1, 2, 3, 4, 5)
    val list3 = List(1, 2)

    //用List匹配
    list1 match {
      case List(0) => println("匹配只有一个元素0")
      case List(0, _*) => println("0___*")
      case List(x, y) => println("x,y")
      case _ => println("未匹配")
    }

    //关键字优化
    list2 match {
      case Nil => println("匹配只有一个元素0")
      case 0 :: tail => println("0___*")
      case x :: y :: Nil => println("x,y")
      case _ => println("未匹配")
    }

  }

}
View Code

G:匹配元组

package com.itheima.moshipipei

//匹配元组
object Demo07 {

  def main(args: Array[String]): Unit = {
    val a = (1, 2, 3)
    val b = (4, 5, 6)

    a match {
      case (1, x, y) => println("长度为3,1开头后两个元素无所谓")
      case (x, y, 5) => println("匹配长度为3,以5结尾,前两个元素无所谓")
      case _ => println("未匹配")
    }
  }

}
View Code

H:变量声明中的模式匹配

val array = (1 to 10).toArray
val Array(_, x, y, z, _*) = array
println(x, y, z)


val list = (1 to 10).toList
val x :: y :: tail = list
println(x, y)
View Code

4. Option类型

  • Some(x):表示实际的值
  • None:表示没有值
  • getorElse():当值为None的时候可以指定一个默认值
package com.itheima.option

object Demo01 {

  def div(a: Int, b: Int) = {
    if (b == 0) {
      None //除数为0没有结果
    } else {
      Some(a / b) //除数不为0,返回具体结果
    }
  }

  def main(args: Array[String]): Unit = {
    var result = div(10, 0)

    result match {
      case Some(x) => println(x)
      case None => println("除数不能为0")
    }

    println("-" * 30)
    println(result.getOrElse(0))
  }

}
View Code

5. 偏函数

package com.itheima.panhuanshu

object Demo01 {

  def main(args: Array[String]): Unit = {
    val ps: PartialFunction[Int, String] = {
      case 1 => "一"
      case 2 => "二"
      case 3 => "三"
      case _ => "其他"
    }

    println(ps(1))

    println(ps(2))
  }

}
View Code
package com.itheima.panhuanshu

object Demo02 {

  def main(args: Array[String]): Unit = {
    val list1 = (1 to 10).toList
    //将1-3的数字转换为【1-3】
    var list2 = list1.map {
      case x if x >= 1 && x <= 3 => "[1-3]"
      case x if x >= 4 && x <= 7 => "[4-8]"
      case _ => "[8-*]"
    }
    println(list2)
  }
}
View Code

6. 正则表达式

package com.itheima.zhengzhe

//案例 正则表达式入门
object Demo01 {
  def main(args: Array[String]): Unit = {
    val mail = "qq123456@163.com"

    /**
      * .表示任意字符
      * +数量词,前面的字符至少出现一次,至多不上限制
      * @  必须出现的
      * \是转义字符
      */
    var regex =
      """.+@.+\..+""".r
    if (regex.findAllMatchIn(mail).size != 0) {
      println("合法邮箱")
      print(regex.findAllMatchIn(mail).toList)
    } else {
      println("非法邮箱")
    }
  }

}
View Code
package com.itheima.zhengzhe

object Demo02 {

  def main(args: Array[String]): Unit = {

    val emlList = List("38123845@qq.com", "a1da88123f@gmail.com", "zhansan@163.com", "123afadff.com")

    val regex=""".+@.+\..+""".r
    val list=emlList.filter(x=>regex.findAllMatchIn(x).size==0)

    println(list)
  }

}
View Code
package com.itheima.zhengzhe

object Demo03 {

  def main(args: Array[String]): Unit = {
    val regex = """.+@(.+)\..+""".r

    val emlList = List("38123845@qq.com", "a1da88123f@gmail.com", "zhansan@163.com", "123afadff.com")

    //根据模式匹配获取所有合法的邮箱及其对应的运营商
    val result = emlList.map {
      //表示emlList中的元素
      //company表示正则表达式括号括起来的内容
      case email@regex(company) => s"邮箱${email}对应的公司是:${company}"
      case email => s"${email}未匹配"
    }

    println(result)

    val re = emlList.map {
      //表示emlList中的元素
      //company表示正则表达式括号括起来的内容
      case email@regex(company) => email -> s"${company}"
      case email => email -> "未匹配"
    }

    println(re)
  }

}
View Code

7. 异常处理

package com.itheima.yichang
//演示try catch
object Demo01 {
  def main(args: Array[String]): Unit = {
      try {
        val i = 10 / 0
      } catch {
        case ex:Exception =>ex.printStackTrace()
      }


    println("你好啊")
  }

}
View Code

8. 提取器

  • 样例类中自动实现了apply,unapply方法,支持模式匹配。
  • 不是所有类的类可以进行这样的模式匹配
  • 要支持模式匹配必须要实现一个提取器
package com.itheima.tiquqi

object Demo02 {

  case class Customer(name: String, age: Int)

  case class Person(id: Int)

  def main(args: Array[String]): Unit = {
    val c: Any = Customer("刘德华", 46)
    val p: Any = Person(1)

    p match {
      case Person(id) => println("这是人")
      case Customer(name, age) => println("这是顾客")
    }
  }

}
View Code

package com.itheima.tiquqi


//演示:scala中的提取器
object Demo01 {

  class Student(var name:String,var age:Int)

  object Student{
    def  apply(name:String,age:Int)=new Student(name,age)

    def unapply(s: Student): Option[(String, Int)] = {
      if(s!=null)
        Some(s.name,s.age)
      else
        None
    }
  }


  def main(args: Array[String]): Unit = {
    val s=new Student("刘德华",12)//普通方式创建对象

    val s1=Student("周",3)

    //通过提取器获取对象中的方法
    val result=Student.unapply(s1)
    println(result)

  }

}
View Code

 9. 泛型

A:泛型方法

package com.itheima.fanxing

//泛指某种数据的类型
//细节:泛型方法在调用方法的时候,明确具体数据类型
object Demo01 {

  //def getMiddleEle(arr:Array[Any])=arr(arr.length/2)
  def getMiddleEle[T](arr: Array[T]) = arr(arr.length / 2)

  def main(args: Array[String]): Unit = {
    println(getMiddleEle(Array(1, 2, 3, 4, 5)))
  }

}
View Code

B:定义泛型类

  • 泛型类是在创建对象的时候明确具体的数据类型
package com.itheima.fanxing


//泛型类:在创建对象的时候,明确数据类型
object Demo02 {
  case class Pair[T](name:T,age:T)
  def main(args: Array[String]): Unit = {
    val pairList = List(
      Pair("Hadoop", "Storm"),
      Pair("Hadoop", 2008),
      Pair(1.0, 2.0),
      Pair("Hadoop", Some(1.9))
    )

    println(pairList)
  }

}
View Code

C:上下界

  • 使用<:类型名表示给类型添加一个上界,表示泛型参数必须是从该类(或本身)继承
  • 使用>:类型名表示给类型添加一个下界,表示泛型参数必须是某个类的父类
  • 如果类既有上界又有下界,下界写在前面,上界写在后面

上界

package com.itheima.fanxing

//演示泛型上界
object Demo03 {

  class Person
  class Student extends Person

  def  demo[T<:Person](arr:Array[T])=println(arr)

  def main(args: Array[String]): Unit = {
    //demo(Array(1,2,3))报错
    demo(Array(new Person))
    //demo(Array(new Student))报错
  }

}
View Code

下界

package com.itheima.fanxing
//演示下界
object Demo04 {
  class Person

  class Policeman extends Person

  class Superman extends Policeman

  def demo[T>:Policeman](array:Array[T])=println(array)

  def main(args: Array[String]): Unit = {
    demo(Array(new Person))
    demo(Array(new Policeman))
    //demo(Array(new Superman))报错
  }

}
View Code

D:协变、逆变、非变

非变

  • class Pair[T]{}
  • 默认泛型是非变的
  • 类型B是A的子类型,Pair[B]和Pair[A]没有任何从属关系
  • java是一样的

协变

  • class Pair[+T]
  • 类型B是类型A的子类,Pair[B]可以认为是Pair[A]的子类型
  • 参数化类型的方向和类型的方向是一致的

逆变

  • class Pair[-T]
  • 参数B是A的子类型,Pair[A]反过来可以认为是Pair[B]的子类型
  • 参数化类型的方向和类型的方向是相反的
package com.itheima.fanxing

//演示:非变
object Demo05 {

  class Super

  class Sub extends Super

  class Temp1[Sub]

  class Temp2[+Sub]

  class Temp3[-Sub]

  def main(args: Array[String]): Unit = {
    val a: Temp1[Sub] = new Demo05() = new Temp1[Sub]
    //编译报错
    //非变
    //val b:Temp1[Super]=a

    //协变
    val c: Temp2[Sub] = new Temp2[Sub]
    val d: Temp2[Super] = c

    //逆变
    val e: Temp3[Super] = new Temp3[Super]
    val f: Temp3[Sub] = e

  }
}
View Code

10. Actor

A:Java并发编程的问题

  在java并发编程中,每个对象都有一个逻辑监视器(monitor),可以用来控制对象的多线程访问。我们添加sychronized关键字来标记,需要进行同步加锁访问,这样通过加锁的机制来确保同一时间只有一个线程访问共享数据,但是这种方式存在资源竞争,以及死锁问题,程序越大越麻烦。

 

B:Actor并发编程模型

  Actor编程是一种基于事件模型的并发机制,一种不共享数据,依赖消息传递的一种并发编程模式,有效避免资源争夺,死锁等情况。

 C:创建Actor

    • 定义class或者object继承Actor特质
    • 重写act方法
    • 调用Actor的start方法执行Actor
    • 类似于java线程,每个Actor是并发执行的
import scala.actors.Actor

//actor 并发编程入门  通过class 创建actor
//用class还是object来创建object的依据是,该Actor对象是否创建多个。单个用object,多个用class
object Demo01 {

  //创建actor1打印1-10的数字
  class Actor1 extends Actor{
    override def act(): Unit = for(i<- 1 to 10) println("actor1----"+i)
  }

  class Actor2 extends Actor{
    override def act(): Unit = for(i<- 11 to 20) println("actor2----"+i)
  }

  def main(args: Array[String]): Unit = {
    new Actor1().start()
    new Actor2().start()
  }

}
View Code
    1. 调用start方法启动Actor
    2. 自动执行act方法
    3. 向Actor发送消息
    4. act方法执行完成后,程序会自动调用exit()方法

 D:发送消息/接受消息

发送消息

 如果要给actor1发送一个异步字符串消息:actor ! “您好”

接收消息

Actor中receive方法来接收消息,需要给receive传入一个偏函数

receive方法直接收一次消息

object Demo04 {


  //创建Sender
  object ActorSender extends Actor{
    override def act(): Unit = {
      while (true){

        ActorReciever ! "你好啊。我是Sender"

        TimeUnit.MILLISECONDS.sleep(3000)
      }

    }
  }

  object ActorReciever extends Actor{
    override def act(): Unit = {
      while(true){
        receive{//传入一个偏函数
          case x:String=>println(x)
        }
      }
    }
  }
  

  def main(args: Array[String]): Unit = {
    ActorSender.start()
    ActorReciever.start()
  }

}
View Code

E:使用loop和react接收优化消息

  使用while(true)会频繁的创建线程,销毁和切换,会影响运行效率

object Demo05 {
  //创建Sender
  object ActorSender extends Actor{
    override def act(): Unit = {
      while (true){

        ActorReciever !"你好啊。我是Sender"

        TimeUnit.MILLISECONDS.sleep(3000)
      }

    }
  }

  object ActorReciever extends Actor{
    override def act(): Unit = {
      loop{
        react{
          case x:String=>println(x)
        }
      }
    }
  }

  //创建Receiver

  def main(args: Array[String]): Unit = {
    ActorSender.start()
    ActorReciever.start()
  }

}
View Code

F:发送和接收自定义消息

package com.itheima.scala.Actor

import scala.actors.Actor

//案例: Actor发送和接收自定义消息, 采用 同步有返回的形式
object Demo06 {

  //1. 定义两个样例类Message(表示发送数据),   ReplyMessage(表示返回数据.)
  case class Message(id: Int, message: String) //自定义的发送消息 样例类
  case class ReplyMessage(message: String, name: String) //自定义的接收消息 样例类


  //2. 创建一个MsgActor,用来接收MainActor发送过来的消息, 并向它回复一条消息.
  object MsgActor extends Actor {
    override def act(): Unit = {
      //2.1 接收 主Actor(MainActor) 发送过来的消息.
      loop {
        react {
          //结合偏函数使用
          case Message(id, message) => println(s"我是MsgActor, 我收到的消息是: ${id}, ${message}")

          //2.2 给MainActor回复一条消息.
          //sender: 获取消息发送方的Actor对象
          sender ! ReplyMessage("我很不好, 熏死了!...", "车磊")
        }
      }
    }
  }

  def main(args: Array[String]): Unit = {
    //3. 开启MsgActor
    MsgActor.start()

    //4. 通过MainActor, 给MsgActor发送一个 Message对象.
    //采用 !?  同步有返回.
    val reply:Any = MsgActor !? Message(1, "你好啊, 我是MainActor, 我在给你发消息!")
    //resutl表示最终接收到的 返回消息.
    val result = reply.asInstanceOf[ReplyMessage]
    //5. 输出结果.
    println(result)
  }
}

package com.itheima.scala.Actor


import scala.actors.Actor

//案例: Actor发送和接收自定义消息, 采用 异步 无返回的形式
object Demo07 {

  //1. 定义两个样例类Message(表示发送数据),   ReplyMessage(表示返回数据.)
  case class Message(id: Int, message: String) //自定义的发送消息 样例类

  //2. 创建一个MsgActor,用来接收MainActor发送过来的消息, 并向它回复一条消息.
  object MsgActor extends Actor {
    override def act(): Unit = {
      //2.1 接收 主Actor(MainActor) 发送过来的消息.
      loop {
        react {
          //结合偏函数使用
          case Message(id, message) => println(s"我是MsgActor, 我收到的消息是: ${id}, ${message}")
        }
      }
    }
  }

  def main(args: Array[String]): Unit = {
    //3. 开启MsgActor
    MsgActor.start()

    //4. 通过MainActor, 给MsgActor发送一个 Message对象.
    //采用 !  异步无返回
   MsgActor ! Message(1, "我是采用 异步无返回 的形式发送消息!")

  }
}


package com.itheima.scala.Actor


import scala.actors.{Actor, Future}


//案例: Actor发送和接收自定义消息, 采用 异步有返回的形式
object Demo08 {

  //1. 定义两个样例类Message(表示发送数据),   ReplyMessage(表示返回数据.)
  case class Message(id: Int, message: String) //自定义的发送消息 样例类
  case class ReplyMessage(message: String, name: String) //自定义的接收消息 样例类


  //2. 创建一个MsgActor,用来接收MainActor发送过来的消息, 并向它回复一条消息.
  object MsgActor extends Actor {
    override def act(): Unit = {
      //2.1 接收 主Actor(MainActor) 发送过来的消息.
      loop {
        react {
          //结合偏函数使用
          case Message(id, message) => println(s"我是MsgActor, 我收到的消息是: ${id}, ${message}")

            //2.2 给MainActor回复一条消息.
            //sender: 获取消息发送方的Actor对象
            sender ! ReplyMessage("我很不好, 熏死了!...", "糖糖")
        }
      }
    }
  }

  def main(args: Array[String]): Unit = {
    //3. 开启MsgActor
    MsgActor.start()

    //4. 通过MainActor, 给MsgActor发送一个 Message对象.
    //采用 !!  异步有返回.
    val future: Future[Any] = MsgActor !! Message(1, "你好啊, 我是MainActor, 我在给你发消息!")

    //5. 因为future中不一定会立马有数据, 所以我们要校验.
    //Future的isSet()可检查是否已经收到返回消息,apply()方法可获取返回数据
    //!future.isSet表示: 没有接收到具体的返回消息, 就一直死循环.
    while(!future.isSet){}

    //通过Future的apply()方法来获取返回的数据.
    val result = future.apply().asInstanceOf[ReplyMessage]
    //5. 输出结果.
    println(result)
  }
}
View Code

 11. WorldCount案例

  需求:在一个文件夹下有多个文件,每个文件中都有若干个单词,单词之间是通过空格隔开。请统计该文件夹下所有的文件中的单词的分别统计个数。

posted @ 2019-11-01 10:53  单词计数程序大牛  阅读(250)  评论(0编辑  收藏  举报