Scala——多范式, 可伸缩, 类似Java的编程语言

时间:2022-07-22
本文章向大家介绍Scala——多范式, 可伸缩, 类似Java的编程语言,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Scala

第一章 是什么

一 Scala 介绍

Scala是一门多范式, 类似java的编程语言 ,设计初衷是实现可伸缩的语言、并集成面向对象编程和函数式编程的各种特性。 Scala以一种简洁、高级的语言将面向对象和函数式编程结合在一起.Scala的静态类型有助于避免复杂应用程序中的bug,它的JVM和JavaScript运行时允许构建高性能的系统,可以轻松地访问庞大的库生态系统。 Spark1.6中使用的是Scala2.10。Spark2.0版本以上使用是Scala2.11版本。 官方网址 https://www.scala-lang.org/

Scala六大特性

  1. 无缝整合JAVA Scala在JVM上运行,因此Java和Scala堆栈可以自由混合,以实现完全无缝集成. 可以相互调用对方的包, 甚至是混编。
  2. 类型自动推断 自动推测识别变量的类型, 类似Python
  3. 并发与分布式 actor:节点之间的通信,是一种通信模型 对集合使用数据并行操作,使用参与者进行并发和分发,或者使用将来进行异步编程。
  4. 特性/特质(类似java中interfaces 和 abstract结合) 将Java风格接口的灵活性与类的强大功能结合起来。有原则的多重继承。
  5. 模式匹配 类似switch语句。与类层次结构、序列等进行匹配。
  6. 高阶函数 一切皆函数, 函数就是方法 函数是第一级的对象.用保证型安全的方式组成它们。在任何地方使用它们,把它们传给任何事物

第二章 Scala 安装使用

一 安装语言环境

  1. windows安装(运行scala-2.11.2.msi 自动安装程序), 配置环境变量 官网下载scala2.10:http://www.scala-lang.org/download/2.10.4.html 下载好后安装(分享至末尾)。 双击msi包安装, 记住安装的路径。 配置环境变量(和配置jdk一样) 新建SCALA_HOME, 指定Scala安装目录; 在配置环境变量Path: %SCALA_HOME%bin
  1. 通过cmd测试是否安装成功

二 常用开发工具整合Scala插件

目的是使当前开发工具能够支持Scala的开发

  • 方式一 eclipse 配置scala插件 1. 下载插件(一定要对应eclipse版本下载) http://scala-ide.org/download/prev-stable.html 2. 下载好zip包后,解压如下:

3.将features和plugins两个文件夹拷贝到eclipse安装目录中的” dropins/scala”目录下。进入dropins,新建scala文件夹,将两个文件夹拷贝到“dropins/scala”下

  • 方式二 scala ide 下载Scala官方整合的eclipse软件开发工具集, 下载打开即可使用 下载网址:http://scala-ide.org/download/sdk.html
  • 方式三 idea 中配置scala插件 打开idea,close项目后,点击Configure->Plugins->输入Scala下载插件 或者通过打开 File->Settings->Plugins->输入Scala下载插件(图1) 图1

三 创建Scala项目

使用IDEA编写Scala代码, 更符合现在公司趋势

  1. 在我们整合Scala以后, 再次创建新的项目就会有Scala选项
  1. 指定项目相关信息 jdk必须为1.8这个大版本 需要指定Scala SDK,这里一开始时没有的,需要我们手动创建, 目录就是我们的Scala的语言环境安装地址

出现这个并选中才是成功配置了Scala开发环境

创建项目成功以后最好是自己配置一下Maven仓库, 指定阿里巴巴镜像仓库, 这样下载jar资源速度更快

如果以上环境都配置完成后, 仍无法 new Scala Class, 请看这里


第三章 Scala 基础

一 数据类型

新增类型的继承关系

部分新增类型的解释

二 变量常量声明

定义变量或者常量的时候,也可以写上返回的类型,一般省略,如:val a:Int = 10 常量不可再赋值

/**
     * 定义变量和常量
     * 变量 :用 var 定义 ,可修改 
     * 常量 :用 val 定义,不可修改
     */
    var name = "TP"
    println(name)
    name ="lisi"
    println(name)
    val gender = "m"
//    gender = "m"//错误,不能给常量再赋值

三 类和对象使用

  1. 创建类 class Person{ val name = "TP" val age = 18 def sayName() = { "my name is "+ name } }
  2. 创建对象 object Lesson_Class { def main(args: Array[String]): Unit = { val person = new Person() println(person.age); println(person.sayName()) } }
  3. 对象中的apply方法 object中不可以传参,当创建一个object时,如果传入参数,那么会自动寻找object中的相应参数个数的apply方法。 /** * object 单例对象中不可以传参, * 如果在创建Object时传入参数,那么会自动根据参数的个数去Object中寻找相应的apply方法 */ object Lesson_ObjectWithParam { def apply(s:String) = { println("name is "+s) } def apply(s:String,age:Int) = { println("name is "+s+",age = "+age) } def main(args: Array[String]): Unit = { Lesson_ObjectWithParam("TP") Lesson_ObjectWithParam("lisi",18) } }
  4. 伴生类和伴生对象 class Person(xname :String , xage :Int){ var name = Person.name val age = xage var gender = "m" def this(name:String,age:Int,g:String){ this(name,age) gender = g } def sayName() = { "my name is "+ name } } object Person { val name = "zhangsanfeng" def main(args: Array[String]): Unit = { val person = new Person("wagnwu",10,"f") println(person.age); println(person.sayName()) println(person.gender) } }

注意:

  • 建议类名首字母大写 ,方法首字母小写,类和方法命名建议符合驼峰命名法。
  • scala 中的object是单例对象,相当于java中的工具类,可以看成是定义静态的方法的类。object不可以传参数。另:Trait不可以传参数
  • scala中的class类默认可以传参数,默认的传参数就是默认的构造函数。 重写构造函数的时候,必须要调用默认的构造函数。
  • class 类属性自带getter ,setter方法。
  • 使用object时,不用new,使用class时要new ,并且new的时候,class中除了方法不执行,其他都执行。
  • 如果在同一个文件中,object对象和class类的名称相同,则这个对象就是这个类的伴生对象,这个类就是这个对象的伴生类。可以互相访问私有变量。

个人学习code

/**
 * 1.Scala中定义常量使用val ,常量不可变,定义变量使用var,变量可变。定义变量和常量时会有类型自动推断机制,可以显式写出变量和常量的类型,一般省略
 * 2.Scala中每行有自动的分号推断机制,不需要在每行后写“;”
 * 3.Scala中有class 和 object,定义class时可以传参,但是参数一定要指定参数类型,给类传参就有默认的构造。
 *   重写构造时,第一行必须先调用默认的构造。
 * 4.Scala中的object相当于java中的单例,类似于Java中的工具类,Object中定义的所有属性和方法都是静态的,调用时直接使用对象名.属性|方法。
 *   Object不可以传参,Trait也不可以传参。
 *
 * 5.在一个Scala文件中,如果class的名称和Object的名称一致,这个class叫做这个object的伴生类,这个object叫做这个class伴生对象,他们之间可以访问私有变量。
 *
 * Create by TimePause
 * Create on 2019/12/10
 */
class Person{
  // 在定义成私有变量后, 如果还想让object获取类的属性, 只需要将二者的名称设置成一样即可
  private var name="TimePause"
  val age="18"

  println("===========================")
}

class Person3(xname:String,xage:Int){
  val name=xname
  val age=xage
  var gender='f'
  def this(yname:String,yage:Int,ygender:Char){
    this(yname,yage)
    this.gender=ygender
  }
  def  showScore(c:String): Unit ={
   // println(s"Class=${c} Score="+ObjetAndClass.score)
  }
}
class Person2(xname:String,xage:Int){
  val name=xname
  val age=xage
}
class Person1{
  val name="TimePause"
  val age="18"
}

object ObjetAndClass {
  // 相当于静态变量/类变量
  val score=66
  // 使用apply方法实现object值的传递
  def apply(s: String, i: Int) = {
    println(s"name=$s age=$i")
  }

  def main(args: Array[String]): Unit = {
    ObjetAndClass("TP",22)

    //println("hello world")
    //尽量使用val, 因为val类型数据更容易被内存回收
    val person=new Person()
   // println(s"person name= ${person.name}")
    println(s"person age="+ person.age)
   // println(s"person gender="+ person.gender)
   // person.showScore("班级1")
  }
}

四 条件语句

  1. if…else
    val age =18 
    if (age < 18 ){
    	println("no allow")
    }else if (18<=age&&age<=20){
    	println("allow with other")
    }else{
    	println("allow self")
    }
  1. for ,while,do…while
 	println(1 to 10 )//打印 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
    println(1.to(10))//与上面等价,打印 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
    println(1 to (10 ,2))//步长为2,从1开始打印 ,1,3,5,7,9
    println(1.to(10, 2)) 
    println(1 until 10 ) //不包含最后一个数,打印 1,2,3,4,5,6,7,8,9
    println(1.until(10))//与上面等价
	println(1 until (10 ,3 ))//步长为2,从1开始打印,打印1,4,7
  1. for循环
 //可以分号隔开,写入多个list赋值的变量,构成多层for循环
    //scala中 不能写count++ count-- 只能写count+
    var count = 0;
    for(i <- 1 to 10; j <- 1 until 10){
      println("i="+ i +",	j="+j)
      count += 1
    }
    println(count);
    
    //例子: 打印小九九
    for(i <- 1 until 10 ;j <- 1 until 10){
      if(i>=j){
    	  print(i +" * " + j + " = "+ i*j+"	")
        
      }
      if(i==j ){
        println()
      }
      
    }
  1. for循环中可以加条件判断,可以使用分号隔开,也可以不使用分号 //可以在for循环中加入条件判断 for(i<- 1 to 10 ;if (i%2) == 0 ;if (i == 4) ){ println(i) }
  2. scala中不能使用count++,count—只能使用count = count+1 ,count += 1
  3. for循环用yield 关键字返回一个集合
  4. while循环,while(){},do {}while()

个人学习code

object IfAndLoopStatement {
  def main(args: Array[String]): Unit = {
    //for循环
    for (i <- 1 to 10) {
      println(i)
    }
    // 打印1 到10
    println(1 to 10) //Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    println(1.to(10)) //Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    println(1.to(10, 2)) //Range(1, 3, 5, 7, 9)
    // 打印 1 到9(10-1)
    println(1 until 10) //Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
  }

  /**
   * 九九乘法表了解一下1
   */
/*  for (i <- 1.to(9)) {
    for (j <- 1.until(10)) {
      if (i >= j) {
        print(s"$i * $j= ${i * j}t")
      }
      if (i == j) {
        println()
      }
    }
  }*/

  /**
   * 九九乘法表2
   * 分号并行书写,自动识别内层循环
   */
  for (i <- 1.to(9) ;j <- 1.until(10)) {
      if (i >= j) {
        print(s"$i * $j= ${i * j}t")
      }
      if (i == j) {
        println()
      }
  }
  println("-----------------------------------")
  //for..if
  for(i <- 1.to(100) if(i%2==0) if(i>50) ){
    print(i+"t")
  }
  //if...else, do...while同java一致
  //while循环语句
  var i=1
  while (i<100){
    println(s"第$i 次考六级")
    i+=1   //需要注意的是这里没有i++
  }
}

第四章 Scala 的方法与函数

一 函数方法的定义

/**
     * 一 单方法定义
     * 1. 方法定义使用def, 方法的参数必须指定参数类型
     * 2. 方法返回值, 可使用return, 也可以省略return, 但不建议使用, 如果使用必须声明方法的返回值类型
     * 3. 方法的返回值类型也可以省略, Scala可以自动推断
     * 4. 如果方法体可以一行搞定, 那么方法体 {} 可以省略
     * 5. 如果定义方法时等号省略, 那么方法体中最后一行无论是什么, 都会被丢弃, 返回Unit/空
     */
    def max(x: Int, y: Int): Int = {
      if (x > y) {
        x
      }
      else {
        y
      }
    }
	//如果方法体中的语句可以一行写完,那么if...else...所在函数可以写成这样
    def max2(x: Int, y: Int): Int = if (x > y) x else y
    
    println(max(666, 888))

二 递归方法

 /**
     * 二 定义递归方法
     * 递归方法必须显示声明方法的返回值类型
     */
    def recursionFun(num: Int): Int = {
      if (num == 1) {
        1
      } else {
        num * recursionFun(num - 1)
      }
    }
    println(recursionFun(5))

运行结果

三 参数有默认值的方法

   /**
     * 三 参数有默认值的方法
     * 1. 默认值的函数中,如果传入的参数个数与函数定义相同,则传入的数值会覆盖默认值
     * 2. 如果不想覆盖默认值,传入的参数个数小于定义的函数的参数,则需要指定参数名称
     */
    def fun(a: Int = 100, b: Int = 200): Int = {
      a + b
    }
    println(fun(b=100))
  }

运行结果

四 可变参数的方法

/**
   * 四 可边长参数的方法
   * 注意:多个参数逗号分开
   */
  def fun1(elems: String*): Unit = {
    for (elem <- elems) {
      println(elem)
    }
  }
  fun1("helloword","h","e","l","l","o")
  /**
   * 五 遍历集合方法/函数
   *
   * @param elems
   */
  def fun2(elems: String*): Unit = {
    //这是最简过程(只有一个参数可以)
    elems.foreach(println)
    //   elems.foreach(println(_))
    //   elems.foreach(one=>{
    //     println(one)
    //   })
  }

  fun2("helloword","h","e","l","l","o")

运行结果

五 匿名函数

 /**
   * 六 匿名函数
   * 1.有参数匿名函数
   * 2.无参数匿名函数
   * 3.有返回值的匿名函数
   * 注意:
   * "=>"就是匿名函数
   * 如何调用匿名函数? 将匿名函数赋值给一个变量
   * 当方法的参数需要传递的参数为函数时,就可使用匿名函数
   */
  var fun3 = () => {
    println("HelloWorld")
  }
  //fun3()
  val fun4: (Int, Int) => Int = (a: Int, b: Int) => {
    a + b
  }
  //println(fun4(100,222))

运行结果

六 嵌套函数/方法

  /**
   * 七 嵌套方法
   * 利用嵌套实现阶乘
   */
  def fun6(a: Int): Int = {
    def fun5(num: Int): Int = {
      if (num == 1) {
        1
      } else {
        num * fun5(num - 1)
      }
    }

    fun5(a)
  }
  println(fun6(5))

运行结果

七 偏应用函数

/**
   * 八 偏应用函数
   * 偏应用函数是一种表达式,不需要提供函数需要的所有参数,只需要提供部分,或不提供所需参数。
   * 从这里可以看出Scala与java无缝整合的特性,因为Scala可以掉Java的相关包,例如java.util.Date
   */
  def showlog(d: Date, log: String): Unit = {
    println(s"时间为: $d, 日志信息为: $log")
  }

  var d = new Date()
  showlog(d, "hello")
  showlog(d, "hello")
  showlog(d, "hello")
  // -代表第一个参数是固定值, 我们可以不写
  var fun7 = showlog(d, _: String);
  fun7("a")
  fun7("b")
  fun7("c")

运行结果

八 高阶函数

  /**
   * 九 高阶函数
   * 函数的参数是函数,或者函数的返回类型是函数,或者函数的参数和函数的返回类型是函数的函数。
   * 1. 方法的参数是函数( 最重要 )
   * 2. 方法的返回值是函数
   * 3. 方法的参数和返回值都是函数
   */
  //1.方法的参数是函数
  def fun8(a: Int, b: Int): Int = {
    a + b
  }

  def fun9(f: (Int, Int) => Int, s: String) = {
    var r: Int = f(10, 20)
    r + "===" + s
  }
  println(fun9(fun8, "方法的参数中传入了函数"))
  println(fun9((a:Int,b:Int)=>{a*b},"使用匿名函数让两个函数相乘"))

  // 2.方法的返回值是函数
  def fun10(a: Int, b: Int): (String, String) => (String) = {
    var r = a + b

    def fun11(s1: String, s2: String): String = {
      r + "===" + s1 + s2
    }
    //这里省略了一个return,代表返回一个函数
    fun11
  }
  println(fun10(10, 20)("a", "b"))

  //3. 方法的参数和返回值都是函数
  def fun12(f: (Int, Int) => Int, i: Int): (String, String) => (String) = {
    val r = f(10, 20) + i

    def fun13(s1: String, s2: String): String = {
      r + "===" + s1 + s2
    }
    fun13
  }
  println(fun12((a: Int, b: Int) => {a * b}, 100)("a", "b"))

运行结果

九 科里化函数

/**
   * 科里化函数
   * ------高阶高数的简化
   */
  def fun14(a: Int, b: Int)(c: Int, d: Int): Int = {
    a + b + c + d
  }
  println(fun14(1, 2)(3, 4))

运行结果


第五章 集合

零 Scala 字符串

  1. String
  2. StringBuilder 可变
  3. string操作方法举例 比较:equals 比较忽略大小写:equalsIgnoreCase indexOf:如果字符串中有传入的assci码对应的值,返回下标
/**
     * String的相关方法用法同Java一致
     */
    val s1="megalo box"
    val s2="MEGALO BOX"
    //判等
    println(s1.equals(s2))
    println(s1.equalsIgnoreCase(s2))
    //返回当前ascall码对应字符是否出现, 如果出现则返回其下标, 如果出现返回-1
    println(s1.indexOf(66))

    //StringBuilder的实验
    val sb=new StringBuilder();
    sb.append("you ")
    sb.append("are ")
    sb.append("my darling~~~")
    println(sb.toString())

运行结果

String相关方法总结

char charAt(int index)
返回指定位置的字符  从0开始
	
int compareTo(Object o)
比较字符串与对象
	
int compareTo(String anotherString)
按字典顺序比较两个字符串
	
int compareToIgnoreCase(String str)
按字典顺序比较两个字符串,不考虑大小写
	
String concat(String str)
将指定字符串连接到此字符串的结尾
	
boolean contentEquals(StringBuffer sb)
将此字符串与指定的 StringBuffer 比较。
	
static String copyValueOf(char[] data)
返回指定数组中表示该字符序列的 String
	
static String copyValueOf(char[] data, int offset, int count)
返回指定数组中表示该字符序列的 String
	
boolean endsWith(String suffix)
测试此字符串是否以指定的后缀结束
	
boolean equals(Object anObject)
将此字符串与指定的对象比较
	
boolean equalsIgnoreCase(String anotherString)
将此 String 与另一个 String 比较,不考虑大小写
	
byte getBytes()
使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中
	
byte[] getBytes(String charsetName
使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中
	
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
将字符从此字符串复制到目标字符数组
	
int hashCode()
返回此字符串的哈希码
16	
int indexOf(int ch)
返回指定字符在此字符串中第一次出现处的索引(输入的是ascii码值)
	
int indexOf(int ch, int fromIndex)
返返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索
	
int indexOf(String str)
返回指定子字符串在此字符串中第一次出现处的索引
	
int indexOf(String str, int fromIndex)
返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
	
String intern()
返回字符串对象的规范化表示形式
	
int lastIndexOf(int ch)
返回指定字符在此字符串中最后一次出现处的索引
	
int lastIndexOf(int ch, int fromIndex)
返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索
	
int lastIndexOf(String str)
返回指定子字符串在此字符串中最右边出现处的索引
	
int lastIndexOf(String str, int fromIndex)
返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
	
int length()
返回此字符串的长度
	
boolean matches(String regex)
告知此字符串是否匹配给定的正则表达式
	
boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
测试两个字符串区域是否相等

boolean regionMatches(int toffset, String other, int ooffset, int len)
测试两个字符串区域是否相等
	
String replace(char oldChar, char newChar)
返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的
	
String replaceAll(String regex, String replacement
使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串
	
String replaceFirst(String regex, String replacement)
使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串
	
String[] split(String regex)
根据给定正则表达式的匹配拆分此字符串
	
String[] split(String regex, int limit)
根据匹配给定的正则表达式来拆分此字符串
	
boolean startsWith(String prefix)
测试此字符串是否以指定的前缀开始
	
boolean startsWith(String prefix, int toffset)
测试此字符串从指定索引开始的子字符串是否以指定前缀开始。
	
CharSequence subSequence(int beginIndex, int endIndex)
返回一个新的字符序列,它是此序列的一个子序列
	
String substring(int beginIndex)
返回一个新的字符串,它是此字符串的一个子字符串
	
String substring(int beginIndex, int endIndex)
返回一个新字符串,它是此字符串的一个子字符串
	
char[] toCharArray()
将此字符串转换为一个新的字符数组
	
String toLowerCase()
使用默认语言环境的规则将此 String 中的所有字符都转换为小写
	
String toLowerCase(Locale locale)
使用给定 Locale 的规则将此 String 中的所有字符都转换为小写
	
String toString()
返回此对象本身(它已经是一个字符串!)
	
String toUpperCase()
使用默认语言环境的规则将此 String 中的所有字符都转换为大写
	
String toUpperCase(Locale locale)
使用给定 Locale 的规则将此 String 中的所有字符都转换为大写
	
String trim()
删除指定字符串的首尾空白符
	
static String valueOf(primitive data type x)
返回指定类型参数的字符串表示形式

一 数组

数组相关方法总结

序号

方法

描述

1

def apply( x: T, xs: T* ): Array[T]

创建指定对象 T 的数组, T 的值可以是 Unit, Double, Float, Long, Int, Char, Short, Byte, Boolean。

2

def concat[T]( xss: Array[T]* ): Array[T]

合并数组

3

def copy( src: AnyRef, srcPos: Int, dest: AnyRef, destPos: Int, length: Int ): Unit

复制一个数组到另一个数组上。相等于 Java’s System.arraycopy(src, srcPos, dest, destPos, length)。

4

def empty[T]: Array[T]

返回长度为 0 的数组

5

def iterate[T]( start: T, len: Int )( f: (T) => T ): Array[T]

返回指定长度数组,每个数组元素为指定函数的返回值。以上实例数组初始值为 0,长度为 3,计算函数为a=>a+1:scala> Array.iterate(0,3)(a=>a+1) ; res1: Array[Int] = Array(0, 1, 2)

6

def fill[T]( n: Int )(elem: => T): Array[T]

返回数组,长度为第一个参数指定,同时每个元素使用第二个参数进行填充。

7

def fill[T]( n1: Int, n2: Int )( elem: => T ): Array[Array[T]]

返回二数组,长度为第一个参数指定,同时每个元素使用第二个参数进行填充。

8

def ofDim[T]( n1: Int ): Array[T]

创建指定长度的数组

9

def ofDim[T]( n1: Int, n2: Int ): Array[Array[T]]

创建二维数组

10

def ofDim[T]( n1: Int, n2: Int, n3: Int ): Array[Array[Array[T]]]

创建三维数组

11

def range( start: Int, end: Int, step: Int ): Array[Int]

创建指定区间内的数组,step 为每个元素间的步长

12

def range( start: Int, end: Int ): Array[Int]

创建指定区间内的数组

13

def tabulate[T]( n: Int )(f: (Int)=> T): Array[T]

返回指定长度数组,每个数组元素为指定函数的返回值,默认从 0 开始。以上实例返回 3 个元素:scala> Array.tabulate(3)(a => a + 5) ; res0: Array[Int] = Array(5, 6, 7)

14

def tabulate[T]( n1: Int, n2: Int )( f: (Int, Int ) => T): Array[Array[T]]

返回指定长度的二维数组,每个数组元素为指定函数的返回值,默认从 0 开始。

object ArrayStudy {
  def main(args: Array[String]): Unit = {
    val arr=Array[String]("w","z","r","y")
    //遍历方式1(最简化)
    arr.foreach(println)
    //遍历方式2(方式1的正式版)
    arr.foreach(one=>{
      println(one)
    })
    //遍历方式3( 最容易理解 )
    for (a <-arr){
      println(a)
    }

    println("数组初始化")
    val arr1=new Array[String](3)
    arr1(0)="y"
    arr1(1)="y"
    arr1(2)="s"
    //arr1.foreach(println)

    println("二维数组定义,初始化,遍历")
    val arr2=new Array[Array[String]](3)
    arr2(0)=Array[String]("y","y","s")
    arr2(1)=Array[String]("c","l","x")
    arr2(2)=Array[String]("c","x","k")
    //遍历1
    arr2.foreach(elem=> elem.foreach(println))
    //遍历2
    for (ar<-arr2; elem<-arr){
      println(elem)
    }

    println("创建数组并初始化,演示concat方法")
    //val arr3=Array[Int](6,6,6)
    val arr3=Array[String]("tp","n","sh")
    val arr4=Array[String]("TP","N","SH")
    val arr5:Array[String]=Array.concat(arr3,arr4)
    arr5.foreach(println)
    println("创建数组并初始化,使用fill填充数组")
    val arr6=Array.fill(3)("hello")
    arr6.foreach(println)

    println("创建可边长字符数组---------------")
    val arrbuf=ArrayBuffer[String]("szxy","wg","tp")
    arrbuf.append("like")
    arrbuf.append("freedom")
    arrbuf.foreach(println)
  }
}

二 List

  1. 创建list val list = List(1,2,3,4) Nil长度为0的list
  2. list遍历 foreach ,for
  3. list方法举例 filter:过滤元素 count:计算符合条件的元素个数 map:对元素操作 flatmap :压扁扁平,先map再flat

flatmap的图解

list相关方法总结

1	def +(elem: A): List[A]
前置一个元素列表
2	def ::(x: A): List[A]
在这个列表的开头添加的元素。
3	def :::(prefix: List[A]): List[A]
增加了一个给定列表中该列表前面的元素。
4	def ::(x: A): List[A]
增加了一个元素x在列表的开头
5	def addString(b: StringBuilder): StringBuilder
追加列表的一个字符串生成器的所有元素。
6	def addString(b: StringBuilder, sep: String): StringBuilder
追加列表的使用分隔字符串一个字符串生成器的所有元素。
7	def apply(n: Int): A
选择通过其在列表中索引的元素
8	def contains(elem: Any): Boolean
测试该列表中是否包含一个给定值作为元素。
9	def copyToArray(xs: Array[A], start: Int, len: Int): Unit
列表的副本元件阵列。填充给定的数组xs与此列表中最多len个元素,在位置开始。
10	def distinct: List[A]
建立从列表中没有任何重复的元素的新列表。
11	def drop(n: Int): List[A]
返回除了第n个的所有元素。
12	def dropRight(n: Int): List[A]
返回除了最后的n个的元素
13	def dropWhile(p: (A) => Boolean): List[A]
丢弃满足谓词的元素最长前缀。
14	def endsWith[B](that: Seq[B]): Boolean
测试列表是否使用给定序列结束。
15	def equals(that: Any): Boolean
equals方法的任意序列。比较该序列到某些其他对象。
16	def exists(p: (A) => Boolean): Boolean
测试谓词是否持有一些列表的元素。
17	def filter(p: (A) => Boolean): List[A]
返回列表满足谓词的所有元素。
18	def forall(p: (A) => Boolean): Boolean
测试谓词是否持有该列表中的所有元素。
19	def foreach(f: (A) => Unit): Unit
应用一个函数f以列表的所有元素。
20	def head: A
选择列表的第一个元素
21	def indexOf(elem: A, from: Int): Int
经过或在某些起始索引查找列表中的一些值第一次出现的索引。
22	def init: List[A]
返回除了最后的所有元素
23	def intersect(that: Seq[A]): List[A]
计算列表和另一序列之间的多重集交集。
24	def isEmpty: Boolean
测试列表是否为空
25	def iterator: Iterator[A]
创建一个新的迭代器中包含的可迭代对象中的所有元素
26	def last: A
返回最后一个元素
27	def lastIndexOf(elem: A, end: Int): Int
之前或在一个给定的最终指数查找的列表中的一些值最后一次出现的索引
28	def length: Int
返回列表的长度
29	def map[B](f: (A) => B): List[B]
通过应用函数以g这个列表中的所有元素构建一个新的集合
30	def max: A
查找最大的元素
31	def min: A
查找最小元素
32	def mkString: String
显示列表的字符串中的所有元素
33	def mkString(sep: String): String
显示的列表中的字符串中使用分隔串的所有元素
34	def reverse: List[A]
返回新列表,在相反的顺序元素
35	def sorted[B >: A]: List[A]
根据排序对列表进行排序
36	def startsWith[B](that: Seq[B], offset: Int): Boolean
测试该列表中是否包含给定的索引处的给定的序列
37	def sum: A
概括这个集合的元素
38	def tail: List[A]
返回除了第一的所有元素
39	def take(n: Int): List[A]
返回前n个元素
40	def takeRight(n: Int): List[A]
返回最后n个元素
41	def toArray: Array[A]
列表以一个数组变换
42	def toBuffer[B >: A]: Buffer[B]
列表以一个可变缓冲器转换
43	def toMap[T, U]: Map[T, U]
此列表的映射转换
44	def toSeq: Seq[A]
列表的序列转换
45	def toSet[B >: A]: Set[B]
列表到集合变换
46	def toString(): String
列表转换为字符串

个人练习code

/**
 * Author TimePause
 * Create  2019-12-11 10:55
 */
object ListStudy {
  def main(args: Array[String]): Unit = {
    /**
     * 不可变长的list
     */
    println("定义list,遍历")
    val list=List[String]("ah","sz","xxgcxy")
    println("方式一,常用")
    list.foreach(println)
    println("方式二")
    for (elem <-list){
      println(elem)
    }


    println("-------list中的map方法用于切分数组元素,将每个切分后的元素放入到一个数组中(一对一)-------")
    // list:集合 Array:数组  通过map方法获得的素组需要我们再次遍历才能得到元素值
    val list2=List[String]("hi boy","hi girl","hi everyone")
    val listMap:List[Array[String]]=list2.map(one=>{one.split(" ")})
    listMap.foreach(one=>{
      println("==========")
      println(one)
      one.foreach(println)
    })

    println("-------list中的flatmap方法用于切分数组元素,将所有切分后的元素放入到一个数组中(一对多)-------")
    //这样我们就可以直接遍历这个对象了
    val strings: List[String] = list2.flatMap(one => {
      one.split(" ")
    })
    strings.foreach(println)

    println("--------filter,过滤作用-------------")
    val strings1: List[String] = list2.filter(one => {
      //one.equals("hi boy")
      !one.equals("hi boy")
    })
    strings1.foreach(println)

   println("--------count,统计元素个数------------")
    val i: Int = list2.count(one => {
      one.equals("hi boy")
    })
    println(i)


    /**
     * 可边长的list
     */
    println("可边长字符串测试")
    val listbuf=new ListBuffer[String]()
    listbuf.append("I")
    listbuf.append("am")
    listbuf.append("the flash")
    println(listbuf)
  }


}

三 Set

  1. 创建set 注意:set集合会自动去重
  2. set遍历 foreach,for
  3. set方法举例 交集:intersect ,& 差集: diff ,&~ 子集:subsetOf 最大:max 最小:min 转成数组,toList 转成字符串:mkString(“~”)

Set相关方法总结

Scala Set 常用方法
下表列出了 Scala Set 常用的方法:
序号	方法 描述
1	
def +(elem: A): Set[A]
为集合添加新元素,x并创建一个新的集合,除非元素已存在
2	
def -(elem: A): Set[A]
移除集合中的元素,并创建一个新的集合
3	
def contains(elem: A): Boolean
如果元素在集合中存在,返回 true,否则返回 false。
4	
def &(that: Set[A]): Set[A]
返回两个集合的交集
5	
def &~(that: Set[A]): Set[A]
返回两个集合的差集
6	
def +(elem1: A, elem2: A, elems: A*): Set[A]
通过添加传入指定集合的元素创建一个新的不可变集合
7	
def ++(elems: A): Set[A]
合并两个集合
8	
def -(elem1: A, elem2: A, elems: A*): Set[A]
通过移除传入指定集合的元素创建一个新的不可变集合
9	
def addString(b: StringBuilder): StringBuilder
将不可变集合的所有元素添加到字符串缓冲区
10	
def addString(b: StringBuilder, sep: String): StringBuilder
将不可变集合的所有元素添加到字符串缓冲区,并使用指定的分隔符
11	
def apply(elem: A)
检测集合中是否包含指定元素
12	
def count(p: (A) => Boolean): Int
计算满足指定条件的集合元素个数
13	
def copyToArray(xs: Array[A], start: Int, len: Int): Unit
复制不可变集合元素到数组
14	
def diff(that: Set[A]): Set[A]
比较两个集合的差集
15	
def drop(n: Int): Set[A]]
返回丢弃前n个元素新集合
16	
def dropRight(n: Int): Set[A]
返回丢弃最后n个元素新集合
17	
def dropWhile(p: (A) => Boolean): Set[A]
从左向右丢弃元素,直到条件p不成立
18	
def equals(that: Any): Boolean
equals 方法可用于任意序列。用于比较系列是否相等。
19	
def exists(p: (A) => Boolean): Boolean
判断不可变集合中指定条件的元素是否存在。
20	
def filter(p: (A) => Boolean): Set[A]
输出符合指定条件的所有不可变集合元素。
21	
def find(p: (A) => Boolean): Option[A]
查找不可变集合中满足指定条件的第一个元素
22	
def forall(p: (A) => Boolean): Boolean
查找不可变集合中满足指定条件的所有元素
23	
def foreach(f: (A) => Unit): Unit
将函数应用到不可变集合的所有元素
24	
def head: A
获取不可变集合的第一个元素
25	
def init: Set[A]
返回所有元素,除了最后一个
26	
def intersect(that: Set[A]): Set[A]
计算两个集合的交集
27	
def isEmpty: Boolean
判断集合是否为空
28	
def iterator: Iterator[A]
创建一个新的迭代器来迭代元素
29	
def last: A
返回最后一个元素
30	
def map[B](f: (A) => B): immutable.Set[B]
通过给定的方法将所有元素重新计算
31	
def max: A
查找最大元素
32	
def min: A
查找最小元素
33	
def mkString: String
集合所有元素作为字符串显示
34	
def mkString(sep: String): String
使用分隔符将集合所有元素作为字符串显示
35	
def product: A
返回不可变集合中数字元素的积。
36	
def size: Int
返回不可变集合元素的数量
37	
def splitAt(n: Int): (Set[A], Set[A])
把不可变集合拆分为两个容器,第一个由前 n 个元素组成,第二个由剩下的元素组成
38	
def subsetOf(that: Set[A]): Boolean
如果集合A中含有子集B返回 true,否则返回false
39	
def sum: A
返回不可变集合中所有数字元素之和
40	
def tail: Set[A]
返回一个不可变集合中除了第一元素之外的其他元素
41	
def take(n: Int): Set[A]
返回前 n 个元素
42	
def takeRight(n: Int):Set[A]
返回后 n 个元素
43	
def toArray: Array[A]
将集合转换为数组
44	
def toBuffer[B >: A]: Buffer[B]
返回缓冲区,包含了不可变集合的所有元素
45	
def toList: List[A]
返回 List,包含了不可变集合的所有元素
46	
def toMap[T, U]: Map[T, U]
返回 Map,包含了不可变集合的所有元素
47	
def toSeq: Seq[A]
返回 Seq,包含了不可变集合的所有元素
48	
def toString(): String
返回一个字符串,以对象来表示

个人学习code

/**
 * Author TimePause
 * Create  2019-12-11 14:20
 */
object SetStudy {
  def main(args: Array[String]): Unit = {

    /**
     * 不可边长
     */
    val set1 = Set[Int](1, 2, 3, 4, 5, 5, 5)
    println("遍历方式一")
    set1.foreach(println)

    println("遍历方式二")
    for (one <- set1){
      println(one)
    }

    println("----intersect:取交集----")
    val set2 = Set[Int](1, 2, 3)
    val set3 = Set[Int](1, 2, 3, 4, 5)
    val ints: Set[Int] = set2.intersect(set3)
    ints.foreach(println)
    println("----diff:差集,必须是大的集合差上小的集合----")
    val ints1: Set[Int] = set3.diff(set2)
    ints1.foreach(println)
    println("----%~作用和diff相同, 但这里必须是小的差上大的集合---")
    val ints3: Set[Int] = set1 &~ set2
    ints3.foreach(println)

    /**
     * 可边长
     * mutable:定位当前set为可变的
     */
    println("----可边长测试-----")
    val strings: mutable.Set[String] = mutable.Set[String]("ah", "sz", "xg")
    strings.add("wg")
    strings.add("tp")
    strings.foreach(println)



  }

}

四 Map

Map相关方法总结

Scala Map 方法
下表列出了 Scala Map 常用的方法:
序号	方法 描述
1	
def ++(xs: Map[(A, B)]): Map[A, B]
返回一个新的 Map,新的 Map xs 组成
2	
def -(elem1: A, elem2: A, elems: A*): Map[A, B]
返回一个新的 Map, 移除 key 为 elem1, elem2 或其他 elems。
3	
def --(xs: GTO[A]): Map[A, B]
返回一个新的 Map, 移除 xs 对象中对应的 key
4	
def get(key: A): Option[B]
返回指定 key 的值
5	
def iterator: Iterator[(A, B)]
创建新的迭代器,并输出 key/value 对
6	
def addString(b: StringBuilder): StringBuilder
将 Map 中的所有元素附加到StringBuilder,可加入分隔符
7	
def addString(b: StringBuilder, sep: String): StringBuilder
将 Map 中的所有元素附加到StringBuilder,可加入分隔符
8	
def apply(key: A): B
返回指定键的值,如果不存在返回 Map 的默认方法
10	
def clone(): Map[A, B]
从一个 Map 复制到另一个 Map
11	
def contains(key: A): Boolean
如果 Map 中存在指定 key,返回 true,否则返回 false。
12	
def copyToArray(xs: Array[(A, B)]): Unit
复制集合到数组
13	
def count(p: ((A, B)) => Boolean): Int
计算满足指定条件的集合元素数量
14	
def default(key: A): B
定义 Map 的默认值,在 key 不存在时返回。
15	
def drop(n: Int): Map[A, B]
返回丢弃前n个元素新集合
16	
def dropRight(n: Int): Map[A, B]
返回丢弃最后n个元素新集合
17	
def dropWhile(p: ((A, B)) => Boolean): Map[A, B]
从左向右丢弃元素,直到条件p不成立
18	
def empty: Map[A, B]
返回相同类型的空 Map
19	
def equals(that: Any): Boolean
如果两个 Map 相等(key/value 均相等),返回true,否则返回false
20	
def exists(p: ((A, B)) => Boolean): Boolean
判断集合中指定条件的元素是否存在
21	
def filter(p: ((A, B))=> Boolean): Map[A, B]
返回满足指定条件的所有集合
22	
def filterKeys(p: (A) => Boolean): Map[A, B]
返回符合指定条件的的不可变 Map
23	
def find(p: ((A, B)) => Boolean): Option[(A, B)]
查找集合中满足指定条件的第一个元素
24	
def foreach(f: ((A, B)) => Unit): Unit
将函数应用到集合的所有元素
25	
def init: Map[A, B]
返回所有元素,除了最后一个
26	
def isEmpty: Boolean
检测 Map 是否为空
27	
def keys: Iterable[A]
返回所有的key/p>
28	
def last: (A, B)
返回最后一个元素
29	
def max: (A, B)
查找最大元素
30	
def min: (A, B)
查找最小元素
31	
def mkString: String
集合所有元素作为字符串显示
32	
def product: (A, B)
返回集合中数字元素的积。
33	
def remove(key: A): Option[B]
移除指定 key
34	
def retain(p: (A, B) => Boolean): Map.this.type
如果符合满足条件的返回 true
35	
def size: Int
返回 Map 元素的个数
36	
def sum: (A, B)
返回集合中所有数字元素之和
37	
def tail: Map[A, B]
返回一个集合中除了第一元素之外的其他元素
38	
def take(n: Int): Map[A, B]
返回前 n 个元素
39	
def takeRight(n: Int): Map[A, B]
返回后 n 个元素
40	
def takeWhile(p: ((A, B)) => Boolean): Map[A, B]
返回满足指定条件的元素
41	
def toArray: Array[(A, B)]
集合转数组
42	
def toBuffer[B >: A]: Buffer[B]
返回缓冲区,包含了 Map 的所有元素
43	
def toList: List[A]
返回 List,包含了 Map 的所有元素
44	
def toSeq: Seq[A]
返回 Seq,包含了 Map 的所有元素
45	
def toSet: Set[A]
返回 Set,包含了 Map 的所有元素
46	
def toString(): String
返回字符串对象

个人学习code

/**
 * Author TimePause
 * Create  2019-12-11 14:59
 */
object MapStudy {
  def main(args: Array[String]): Unit = {
    /**
     * 不可变长
     * map:k-v, 初始化方式可以为k->v(将k映射到v上), (k,v)
     * 因此在遍历语句 for循环中, elem<-map代表将mao集合中的所有元素映射到elem上, 然后我们通过${elem._1},${elem._2}获取其k,v值
     */
      val map=Map[String,Int]("chy"->18,"zwer"->19,("xy",20),("xy",21))
      for (elem<-map){
        println(s"key=${elem._1} ,value=${elem._2}")
      }

    println("获取map的v, 如果有返回Some(v),没有返回None. 可以再通过一个get去除Some")
    val maybeInt: Option[Int] = map.get("chy")
    val maybeInt2= map.get("chy").get
    //如果能找到k,返回v,找不到返回666,返回参数可自定义
    val maybeInt3= map.get("chy1").getOrElse(666)
    println(maybeInt)
    println(maybeInt2)
    println(maybeInt3)

    println("keys : 用于获取所有key")
    val keys: Iterable[String] = map.keys
    keys.foreach(println)   //只获取k
    for (key<-keys){
      println(s"key:${key}, value:${map.get(key).getOrElse(666)}")  //同时获取k,v
    }

    println("values: 获取所有value")
    val values: Iterable[Int] = map.values
    values.foreach(println)

    println("set中的filter方法,count等方法这里也有")
    val stringToInt: Map[String, Int] = map.filter(tp => {
      "chy".equals(tp._1)
    })
    stringToInt.foreach(println)

    println("++将后面的map放到前面的map, ++: 则是相反(貌似现在用不了了)")
    val map1=Map[String,Int]("a站"->6,"b站"->8,"c站"->7)
    val map2=Map[String,Int]("a站"->66,"b站"->88,"c站"->77,("d站",99))
    val mapadd: Map[String, Int] = map1.++(map2)
    for (tp<-mapadd){
      println(s"k=${tp._1},value:${tp._2}")
    }


    /**
     * 可边长map
     */
      println("可边长map-----------")
    val muMap: mutable.Map[String, Int] = mutable.Map[String, Int](("a", 1))
    muMap.put("b",2)
    muMap.foreach(println)
  }
}

五 元组

  1. 元组定义 与列表一样,与列表不同的是元组可以包含不同类型的元素。元组的值是通过将单个的值包含在圆括号中构成的。
  2. 创建元组与取值 val tuple = new Tuple(1) 可以使用new val tuple2 = Tuple(1,2) 可以不使用new,也可以直接写成val tuple3 =(1,2,3) 取值用”._XX” 可以获取元组中的值 注意:tuple最多支持22个参数
  3. 元组的遍历 tuple.productIterator得到迭代器,进而遍历
  4. swap,toString方法 注意:swap元素翻转,只针对二元组
  /**
   * Author TimePause
   * Create  2019-12-11 17:28
   */
  object TupleStudy {
    def main(args: Array[String]): Unit = {
      /**
       *Tuple:元组 与list一样,只不过每个元素都对应一个类型. 最多支持22个元素
       * 注意:
       *    1. 定义tuple时, 三种方式new,也可以不用new,直接写()填写元素,最多22个
       *    2. tuple[n] : n 代表tuple中需要添加元素的个数
       *    3. tuple取值, tuple位置
       *    4. 遍历tuple:使用tuple.productIterator 得到一个迭代器, 遍历迭代器即可
       */
        println("------------tuple创建元组与取值-------------")
      val tuple: Tuple1[String] = new Tuple1("hello")
      val tuple2: (String, Int) = new Tuple2("hello", 10)
      //    println(s"key = ${tuple2._1},value = ${tuple2._2}")

      val tuple3 = new Tuple3(1, true, 1.5f)
      println("---"+tuple3.toString())
      val tuple4 = new Tuple4(1,2,3,4)
      val tuple5 = Tuple5(1,2.5f,"hello world",'c',true)
      //    println(tuple5._5)
      val tuple6 = (1,2,3,4,"hello world",6,7,8)
      //    println(tuple6._5)
      val tuple22: (Int, Boolean, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) = (1, true, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22)

      println("---------tuple的遍历---------")
      val iter: Iterator[Any] = tuple5.productIterator
      iter.foreach(println)
      //    while(iter.hasNext){
      //      println(iter.next())
      //    }

      /**
       * 注意:swap元素翻转,只针对二元组
       */
      println(tuple2.swap)

    }
  }

第六章 Scala 高级知识

一 trait 特性

  1. 概念理解 Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。 与接口不同的是,它还可以定义属性和方法的实现。 一般情况下Scala的类可以继承多个Trait,从结果来看就是实现了多重继承。Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait。
  2. 举例:trait中带属性带方法实现 注意: 继承的多个trait中如果有同名的方法和属性,必须要在类中使用“override”重新定义。 trait中不可以传参数
  3. 举例:trait中带方法不实现

学习code

/**
 * trait中可以定义变量和常量, 也可以定义方法的实现和不实现, 一个类可以继承多个trait
 *  注意: 一个类继承多个trait时, 第一个使用 extends,后面的使用 with
 *
 * Author TimePause
 * Create  2019-12-11 19:41
 */
//案例一
trait Read{
 // val age=1
  def read(name:String): Unit ={
    println(s"$name is reading...")
  }
}

trait Listen{
 // val age=2
  def listen(name:String): Unit ={
    println(s"$name is listenning")
  }
}
class Persons(xname:String,age:Int) extends Read with  Listen {
  val name=xname
 // override val age: Int = 30
}

//案例二
trait MyEQU{
  def isEQU(o:Any):Boolean
  def isNotEQU(o:Any):Boolean= !isEQU(o)
}
class  Point(xx:Int,xy:Int) extends  MyEQU {
    val x=xx;
    val y=xy;

  override def isEQU(o: Any): Boolean = {
    // isInstanceOf是否是某个类. asInstanceOf作为后面的类型
    o.isInstanceOf[Point]&& o.asInstanceOf[Point].x==this.x;
  }
}

object TraitStudy {
  def main(args: Array[String]): Unit = {
    val persons: Persons = new Persons("tp", 18)
    persons.read("tp")
    persons.listen("tp")

    val p1=new Point(1,2)
    val p2=new Point(1,3)
    println(p1.isEQU(p2))
    println(p1.isNotEQU(p2))
  }
}

二 样例类 CaseClass

概念理解 使用了case关键字的类定义就是样例类(case classes),样例类是种特殊的类。实现了类构造参数的getter方法(构造参数默认被声明为val),当构造参数是声明为var类型的,它将帮你实现setter和getter方法。

  • 样例类默认帮你实现了toString,equals,copy和hashCode等方法。
  • 样例类可以new, 也可以不用new
/**
 * 样例类
 * 样例类默认实现了toString,equals,copy和hashCode等方法
 * 样例类可以使用new 创建, 也可以不使用
 *
 * Author TimePause
 * Create  2019-12-11 20:22
 */
case class man(xname:String,xage:Int){

}

object CaseClassStudy {
  def main(args: Array[String]): Unit = {
    val h1 =new man("chy",22)
    val h2 =man("chy",22)
    println(h1.equals(h2))
  }
}

三 模式匹配 Match

  1. 概念理解: Scala 提供了强大的模式匹配机制,应用也非常广泛。 一个模式匹配包含了一系列备选项,每个都开始于关键字 case。 每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。
  2. 代码及注意点 模式匹配不仅可以匹配值还可以匹配类型 从上到下顺序匹配,如果匹配到则不再往下匹配 都匹配不上时,会匹配到case _ ,相当于default match 的最外面的”{ }”可以去掉看成一个语句
  3. 偏函数 如果一个方法中没有match 只有case,这个函数可以定义成PartialFunction偏函数。偏函数定义时,不能使用括号传参,默认定义PartialFunction中传入一个值,匹配上了对应的case,返回一个值,只能匹配同种类型。
/**
 *
 * match scala中的模式匹配
 *   注意:
 *     1.Scala中的模式匹配关键字是Match
 *     2.Match模式匹配中不仅可以匹配值,还可以匹配类型,且可以混在一起写。
 *     3.case _=>{.. .. .}代表什么都匹配不上的默认匹配,放在最后
 *     4.匹配的过程中,如果匹配上之后会自动终止。
 *     5.Match匹配的过程中有数值的转换
 */
object MatchStudy {
  def main(args: Array[String]): Unit = {
    val tuple = (1, 1.1, true, "hello", 'c', 1.4f)
    val iter: Iterator[Any] = tuple.productIterator
    iter.foreach(MatchTest)
  }

  /**
   * MatchTest只是一个方法,重要的是方法里面的 match...case语句
   * _代表如果匹配所有,在这里的意思是如果前面的都没有匹配到,匹配这里(默认值)
   */
  def MatchTest(o:Any) =
    o match {
      case i:Int=>println(s"type is Int ,value is $i")
      case 1 =>println("value is 1")
      case b:Boolean=>println(s"type is Boolean ,value is $b")
      case d:Double =>println(s"type is Double ,value is $d")
      case "hello"=>println("value is hello")
      case 'c'=>{println("value is c")}
      case _=>println("no ... match ... ")

    }

	/**
	  * 一个函数中只有case 没有match ,可以定义成PartailFunction 偏函数
	  */
	object Lesson_PartialFunction {
	  def MyTest : PartialFunction[String,String] = {
	    case "scala" =>{"scala"}
	    case "hello"=>{"hello"}
	    case _=> {"no  match ..."}
	  }

}

四 偏函数

如果一个方法中没有match 只有case,这个函数可以定义成PartialFunction偏函数。偏函数定义时,不能使用括号传参,默认定义PartialFunction中传入一个值,匹配上了对应的case,返回一个值,只能匹配同种类型。

/**
 * 偏函数, 完全类似java中的switch...case...语句
 *
 * Author TimePause
 * Create  2019-12-12 9:12
 */
object PartitionFunStudy {
  def MyFun:PartialFunction[String,String]={
    case "1" =>{"一等奖"}
    case "2"=>{"二等奖"}
    case "3"=>{"三等奖"}
    case _=>{"优秀奖"}
  }

  def main(args: Array[String]): Unit = {
    println(MyFun("ss"))

  }
}

五 隐式转换

隐式转换是在Scala编译器进行类型匹配时,如果找不到合适的类型,那么隐式转换会让编译器在作用范围内自动推导出来合适的类型。

1. 隐式值与隐式参数 隐式值是指在定义参数时前面加上implicit。隐式参数是指在定义方法时,方法中的部分参数是由implicit修饰【必须使用柯里化的方式,将隐式参数写在后面的括号中】。隐式转换作用就是:当调用方法时,不必手动传入方法中的隐式参数,Scala会自动在作用域范围内寻找隐式值自动传入。

隐式值和隐式参数注意:

  • 同类型的参数的隐式值只能在作用域内出现一次,同一个作用域内不能定义多个类型一样的隐式值。
  • implicit 关键字必须放在隐式参数定义的开头
  • 一个方法只有一个参数是隐式转换参数时,那么可以直接定义implicit关键字修饰的参数,调用时直接创建类型不传入参数即可。
  • 一个方法如果有多个参数,要实现部分参数的隐式转换,必须使用柯里化这种方式,隐式关键字出现在后面,只能出现一次

2.隐式转换函数

隐式转换函数是使用关键字implicit修饰的方法。当Scala运行时,假设如果A类型变量调用了method()这个方法,发现A类型的变量没有method()方法,而B类型有此method()方法,会在作用域中寻找有没有隐式转换函数将A类型转换成B类型,如果有隐式转换函数,那么A类型就可以调用method()这个方法。

隐式转换函数注意:隐式转换函数只与函数的参数类型和返回类型有关,与函数名称无关,所以作用域内不能有相同的参数类型和返回类型的不同名称隐式转换函数。

3. 隐式类 使用implicit关键字修饰的类就是隐式类。若一个变量A没有某些方法或者某些变量时,而这个变量A可以调用某些方法或者某些变量时,可以定义一个隐式类,隐式类中定义这些方法或者变量,隐式类中传入A即可。

隐式类注意:

  • .隐式类必须定义在类,包对象,伴生对象中。
  • 隐式类的构造必须只有一个参数,同一个类,包对象,伴生对象中不能出现同类型构造的隐式类。
/**
 * 隐式转换implicit
 *  1.隐式值和隐式参数
 *      1)作用域内,相同类型的隐式值只能声明一个
 *      2)一个方法中部分参数是隐式参数, 只能使用科里化方式来定义.将隐式的参数单独放到一个参数表中,不需要的放第一个括号里,使用时直接赋值即可
 *      3)调用隐式方法时, 可以覆盖隐式参数/值
 *  2.隐式转换函数
 *      作用域中不能有相同的 参数类型 和 返回类型 的不同名称的隐式转换函数
 *  3.隐式类
 *      在类的前面加上关键字implicit, 必须定义在object和class中
 *      隐式类中的所有属性方法都可以被调用
 *      隐式类和隐式转换函数非常像
 *
 * Author TimePause
 * Create  2019-12-12 9:27
 */
object Implicitl {
  implicit  var name="TimePause"
  implicit  var age=18

  //案例一
  def people(implicit name:String): Unit ={
    println(s"Hello ${name}")
  }

  def people2(sex:String)(implicit name:String,age:Int): Unit ={
    println(s"Hello ${name}, age:${name}, sex: ${sex}")
  }

  //案例二
  class Bird(bname:String){
    var name=bname;
    def canFly(): Unit ={
        println(s"${name} able fly!")
    }
  }
  class  Pig(pname:String){
    var name=pname
  }

  //案例三
 implicit class Bird1(p:Pig1){
    var name=p.name
    var pvalue="9.15"
    def canFly(): Unit ={
      println(s"${name} able fly!")
    }
  }
  class  Pig1(pname:String){
    var name=pname
  }


  def main(args: Array[String]): Unit = {
    people
    people2("男")

    //使用隐式转换函数(p:Pig): Bird, pig是规定传入参数的类型, Bird规定的返回值的类型
    // 令我们可以通过pig调用bird的fly方法
    implicit  def pigToBird(p:Pig): Bird ={
        new Bird(p.name)
    }
    val pig = new Pig("yyx")
    pig.canFly()

    //重点掌握上面两种即可
    val pig1 = new Pig1("wwk")
    pig1.canFly()
    pig1.pvalue
  }
}

六 Actor Model (Actor通信模型)

概念理解 Actor Model是用来编写并行计算或分布式系统的高层次抽象(类似java中的Thread)让程序员不必为多线程模式下共享锁而烦恼,被用在Erlang 语言上, 高可用性99.9999999 % 一年只有31ms 宕机. Actors将状态和行为封装在一个轻量的进程/线程中,但是不和其他Actors分享状态,每个Actors有自己的世界观,当需要和其他Actors交互时,通过发送事件和消息,发送是异步的,非堵塞的(fire-andforget)发送消息后不必等另外Actors回复,也不必暂停,每个Actors有自己的消息队列,进来的消息按先来后到排列,这就有很好的并发策略和可伸缩性,可以建立性能很好的事件驱动系统。

Actor的特征:

  • ActorModel是消息传递模型,基本特征就是消息传递
  • 消息发送是异步的,非阻塞的
  • 消息一旦发送成功,不能修改
  • Actor之间传递时,自己决定决定去检查消息,而不是一直等待,是异步非阻塞的
  • Actor被实例化后只能用于给自身类发送信息

什么是Akka Akka 是一个用 Scala 编写的库,用于简化编写容错的、高可伸缩性的 Java 和Scala 的 Actor 模型应用,底层实现就是Actor,Akka是一个开发库和运行环境,可以用于构建高并发、分布式、可容错、事件驱动的基于JVM的应用。使构建高并发的分布式应用更加容易。 spark1.6版本之前,spark分布式节点之间的消息传递使用的就是Akka,底层也就是actor实现的。1.6之后使用的netty传输。

import scala.actors.Actor

/**
 * Actor通信模型
 * 需要准备, 面试可能会要求要写, 以备不时之需
 *
 * 步骤
 *  1.创建两个class类,继承Actor, 重新act()方法, 在方法内书写业务逻辑 receive方法代表接收器case匹配聊天内容
 *  2.Actor被实例化后只能用于给自身发送信息. 因为如果要给其他人发送信息需要有 ip+port
 *  3.如果需要给其他Actor发送信息, 需要在自己的Actor实现类中实例化对方类, 通过对方类的对象来给自己发送信息
 *  4.样例类MSG2 : 相当于java中的实体类, 用于规定规定case接收的数据类型模型
 *  5.在Scala类中实例化上面两个类,启动Actor线程
 */
case class MSG2(actor : Actor, msg : String)

class MyActor3 extends  Actor{
  override def act(): Unit = {
    while(true) {
      receive{
        case m : MSG2  =>{
          println(m.msg)
          val actor4 = m.actor
          actor4 ! "hello"
        }
        case s:String=>{println(s"MyActor3 say:${s}")}
        case _=>{println("MyActor receiveMessage fail")}
      }
    }
  }
}
class MyActor4(act3:Actor) extends  Actor{
  act3 ! MSG2(this, "MyActor4: hi Actor3")
  override def act(): Unit = {
    while(true) {
      receive{
        case s:String=>{
          if (s.equals("hello")) {
             println("MyActor4: hi")
          }
        }
        case _=>{println("MyActor sendMessage fail")}
      }
    }
  }
}

object TestActorForMe {
  def main(args: Array[String]): Unit = {
    val actor3 = new MyActor3()
    actor3 !"hello"
    val actor4 = new MyActor4(actor3)
    actor3.start()
    actor4.start()

  }
}

第七章 搭建Spark运行环境

一 环境搭建

  1. 安装并配置Maven(本人java高级技术中有)
  2. Idea创建Maven项目,选择 quickstart
  1. 将原来pom文件中 properties文件及以下删除, 换为本人上传的 Spark的pom配置文件, 稍等片刻待系统缓存相关jar包
  2. 缓存完成后, 在main目录下新建一个 scala 目录, 用于编写scala代码实现Spark, 和java代码进行比较
  3. 打开 Project Stucture 设置,按下图将scala目录提升为可编译的源目录
  1. 书写代码

二 WordCount实现(Scala)

非简化版

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

/**
 * 非简化版
 *匿名函数只有一次可以用下划线简化进行表示
 * Author TimePause
 * Create  2019-12-12 19:17
 */
object SparkWordCount {
  def main(args: Array[String]): Unit = {
    // 创建Spark的配置文件
    val conf: SparkConf = new SparkConf()
    conf.setMaster("local")
    conf.setAppName("SparkWordCount")
    val context = new SparkContext(conf)

    val lines: RDD[String] = context.textFile("./data/word.txt")
    val words: RDD[String] = lines.flatMap(line => {
      line.split(" ")
    })
    // 将word字符串放到二元组中,key代表单词,v代表该单词出现次数
    val wordMap: RDD[(String, Int)] = words.map(word => {
      Tuple2(word, 1)
    }) 

    // 按照相同的key进行分组, 在对每个组的v进行操作
    val result: RDD[(String, Int)] = wordMap.reduceByKey((v1, v2) => {
      v1 + v2
    })
    /*对结果进行排序,默认true,正序*/
    val value = result.sortBy(tp => tp._2, false)
    /*通过swap转换然后通过sortByKey进行排序*/
    //val value = result.map(tp => {tp.swap}) .sortByKey(false)  //or   result.map(tp=>{tp._2,tp._1})
    value.foreach(println)

    //释放SparkContext的对象
    context.stop();
  }
}

简化版

必须熟练默写, 面试必会!!!

**
 * 简化版
 *匿名函数只有一次可以用下划线简化进行表示
 * Author TimePause
 * Create  2019-12-12 19:17
 */
object SparkWordCount2 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local").setAppName("SparkWordCount")
    val context = new SparkContext(conf)
    val lines = context.textFile("./data/word.txt").flatMap(_.split(" ")).map((_, 1)).reduceByKey(_+_).sortBy(_._2,false).foreach(println)
    context.stop();
  }
}

三 WordCount实现(Java)

非简化版

基于Scala实现wordcount:非简化版 JavaRDD: 某种类型的RDD mapTOPair->将非kv格式rdd转成kv格式rdd reduceByKey必须作用在PairRDD上 JavaPairRDD :二元组类型RDD,k,v

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import org.apache.spark.api.java.function.VoidFunction;
import scala.Tuple2;

import java.util.Arrays;
import java.util.Iterator;

/**
 * Java实现Spark方式的wordcount
 *
 * @author TimePause
 * @create 2019-12-12 21:20
 */
public class JavaWordCount {
    public static void main(String[] args) {
        /**
         * SparkConf就是Spark的配置信息,可以配置以下内容:
         *  1.可以配置Spark的运行模式
         *       local:本地运行, 多用于测试, 在eclipse, Idea中使用 SParkConf.setMaster("local")
         *       standalone:Spark自带的资源调度框架, 支持分布式搭建, Spark任务可以运行在Standalone, 集群命令提交
         *       yarn:Hadoop生态圈中的资源调度框架, Spark可以运行在yarn, 集群命令提交
         *       mesos:资源调度框架
         *  2.配置当前application运行的名称 conf.setAppName("wc")
         *  3.配置当前application资源使用信息, conf.set(K,V)
         */
        SparkConf conf = new SparkConf();
        conf.setMaster("local");
        conf.setAppName("wc");
        // javaSparkContext: 是Spark的上下文, 通过集群的唯一通道
        JavaSparkContext sc = new JavaSparkContext(conf);
        JavaRDD<String> lines = sc.textFile("./data/word.txt");
        // 将单词分词
        JavaRDD<String> words = lines.flatMap(new FlatMapFunction<String, String>() {
            @Override
            public Iterator<String> call(String line) throws Exception {
                return Arrays.asList(line.split(" ")).iterator();
            }
        });

        //使用mapToPair将JavaRDD转成JavaPairRDD
        //转换后使用tuple返回, 且key为单词名称, value为词频
        JavaPairRDD<String, Integer> javaPairRDD = words.mapToPair(new PairFunction<String, String, Integer>() {
            @Override
            public Tuple2<String, Integer> call(String word) throws Exception {
                return new Tuple2<String, Integer>(word, 1);
            }
        });

        // 按照相同的key进行分组, 在对每个组的v进行操作
        JavaPairRDD<String, Integer> reduceResult = javaPairRDD.reduceByKey(new Function2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer v1, Integer v2) throws Exception {
                return v1 + v2;
            }
        });
        //排序操作1, 放入一个tuple数据, 返回一个kv数据
        JavaPairRDD<Integer, String> swapRDD = reduceResult.mapToPair(new PairFunction<Tuple2<String, Integer>, Integer, String>() {
            @Override
            public Tuple2<Integer, String> call(Tuple2<String, Integer> integerStringTuple2) throws Exception {
                return integerStringTuple2.swap();
            }
        });
        //排序操作2,调用api的sortByKey
        JavaPairRDD<Integer, String> sortByKeyRDD = swapRDD.sortByKey(false);
        //排序操作3,将排序好的集合再次转换成二元组
        JavaPairRDD<String, Integer> result = sortByKeyRDD.mapToPair(new PairFunction<Tuple2<Integer, String>, String, Integer>() {
            @Override
            public Tuple2<String, Integer> call(Tuple2<Integer, String> integerStringTuple2) throws Exception {
                return integerStringTuple2.swap();
            }
        });

        result.foreach(new VoidFunction<Tuple2<String, Integer>>() {
            @Override
            public void call(Tuple2<String, Integer> tuple2) throws Exception {
                System.out.println(tuple2);
            }
        });
        sc.stop();
    }
}

简化版

public class SparkWordCount {
    public static void main(String[] args) {

        SparkConf conf = new SparkConf();
        conf.setMaster("local");
        conf.setAppName("wc");
        JavaSparkContext sc = new JavaSparkContext(conf);
        sc.textFile("./data/words").flatMap(line -> Arrays.asList(line.split(" ")).iterator()).mapToPair(word -> new Tuple2<>(word, 1)).reduceByKey((v1, v2) -> v1 + v2).foreach(tuple2 -> System.out.println(tuple2));

        sc.stop();

//        SparkConf conf = new SparkConf();
//        conf.setMaster("local");
//        conf.setAppName("wc");
//        JavaSparkContext sc = new JavaSparkContext(conf);
//        JavaRDD<String> lines = sc.textFile("./data/words");
//        JavaRDD<String> words = lines.flatMap(line -> Arrays.asList(line.split(" ")).iterator());
//
//        JavaPairRDD<String, Integer> pairWords = words.mapToPair(word -> new Tuple2<>(word, 1));
//
//        JavaPairRDD<String, Integer> result = pairWords.reduceByKey((v1, v2) -> v1 + v2);
//        result.foreach(tuple2 -> System.out.println(tuple2));
//
//        sc.stop();


    }
}

链接:https://pan.baidu.com/s/1XNIbgV6dMF9_hVrcLrga4A 提取码:ef0f