首页 > 技术文章 > 0 Scala

chen8023miss 2019-07-22 13:00 原文

0 Scala简介

  • Scala是一门多范式的编程语言,一种类似java的编程语言 ,设计初衷是实现可伸缩的语言 、并集成面向对象编程和函数式编程的各种特性。

1 Scala环境

1.1 语言介绍

  • 他已经出生15年了,就像明星一样,谁都不可能一开始就人气爆棚粉丝无数,得慢慢混。

  • 据说这家伙已经威胁到了Java的地位,我当时也是被这句话惊到,才毅然决然的认识了他。目前也正在努力学习中。估计到目前为止国内没有谁敢说已经精通Scala了。当然我猜测有绝大一部分人是为了装那个啥才去学他的,说实话学了他确实可以装那个啥,毕竟很实用,而且学的人不多,学会的人更不多,能熟练运用的人更是少之又少。

  • 大家肯定都有个疑问,为什么Scala这么受欢迎到底是哪里吸引了大家?捡重点说吧,篇幅不宜太多。

  • 身世介绍
    • Scala在2004年正式问世,他的爸爸是Martin Odersky,这位老头同时也是Genenric Java的爸爸。神不神奇!Scala和Genenric Java居然是亲兄弟。不认识Genenric Java的小伙伴们,请自行百度吧。
    • Scala的全称叫scalable,可伸缩的意思。说白了就是可以简单又可以复杂。scala是个纯正的面向对象语言,并且具备函数式编程特性,这也是他最吸引人的地方。另外还有个更更加吸引人的地方(至少对于我这枚Java汪来说)就是他是构建在jvm之上的,因此他可以和Java进行无缝互操作,也就是说scala可以使用Java的类库,java有可以使用scala程序。我觉的单凭这些就已经足够可以引起每一位Java程序员的兴趣。
    • Scala之所以这么受欢迎还有一个原因,那就是Spark。专为大规模数据处理而设计的快速通用的计算引擎,这正是spark的最好诠释,关于spark的更多信息请百度。spark就是Scala编写的,所以想了解spark的优越性能及应用就必须得学习Scala。

  Twitter相比大家都知道,其内部应用大量使用Scala。而在国内,使用Scala的公司还不是很多。但可以预见,Scala时代即将到来。

1.2 下载 Scala

  我们可以从 Scala 官网地址 http://www.scala-lang.org/downloads 下载 Scala 二进制包(页面底部),本教程我们将下载 2.10.5版本,如下图所示:
    

 

1.3 Windos安装Scala (需要java环境)

解决windos一定会出的问题:安装msi 提示2502、2503的错误代码

  • 步骤一:
    • 1、按WIN+R,在运行框中输入“gpedit.msc” 确认;
    • 2、打开本地策略组编辑器后依次展开 :“计算机配置”-》“管理模板”-》“windows组件”-》“windows installer”,并找到“始终以提升的权限进行安装”;
    • 3、双击该选项,设置为“已启用”,并应用;
    • 4、最后我们还要在本地策略组编辑器中的【用户配置】中进行同样的操作;
  • 步骤二:
    • 1、鼠标移到桌面左下角->右键(或者直接: WIN+X键),命令提示符(管理员);
    • 2、输入:msiexec /package +‘msi文件路径’(输入的时候注意半角字符且路径不能为中文名)
    • 例如:C:\Windows\system32>msiexec /package "F:\micsoft\scala\scala-2.10.5.msi"”
  • 步骤三:配置环境变量

    设置 SCALA_HOME 变量:单击新建,在变量名栏输入:SCALA_HOME: 变量值一栏输入:D:\Program Files(x86)\scala 也就是 Scala 的安装目录,根据个人情况有所不同,如果安装在 C 盘,将 D 改成 C 即可。
  • 设置 Classpath 变量:找到找到系统变量下的"Classpath"如图,单击编辑,如没有,则单击"新建":
    • "变量名":ClassPath
    • "变量值":.;%SCALA_HOME%\bin;%SCALA_HOME%\lib\dt.jar;%SCALA_HOME%\lib\tools.jar;
  • 注意:"变量值"最前面的 .; 不要漏掉。最后单击确定即可。
  • 设置 Path 变量:找到系统变量下的"Path"如图,单击编辑。在"变量值"一栏的最前面添加如下的路径: %SCALA_HOME%\bin;%SCALA_HOME%\jre\bin;
  • 注意:后面的分号 ; 不要漏掉。

1.4 linux 装 Scala(需要java环境)

上传scala的tar包到linux解压

修改环境变量

vim ~/.bashrc

在文件的末尾加入:

export PATH="$PATH:/usr/local/src/scala-2.10.5/bin"


更新源后测试

source ~/.bashrc

  • Scala 中文乱码解决
    • 在 Scala 2.11.7 版本上,Mac OS X 或 Linux 系统上编译 Scala 代码,如果出现中文,会出现乱码的情况。
    • 解决方案如下,分别编辑以下两个执行脚本:
$ vim `which scala` 

$ vim `which scalac` 

找到:

[ -n "$JAVA_OPTS" ] || JAVA_OPTS="-Xmx256M -Xms32M"

将其替换为:

[ -n "$JAVA_OPTS" ] || JAVA_OPTS="-Xmx256M -Xms32M -Dfile.encoding=UTF-8"

重新编译脚本,既可以正常显示中文。

1.5-idea配置scala

settings----plugins





    /**
    * author Heaton
    * email tzy70416450@163.com
    * describe HelloWorld
    */
  object HelloWorld {
    def main(args: Array[String]): Unit = {
      println("Hello World")
    }
  }

2 数据类型



  • Scala中定义变量使用var,定义常量使用val ,变量可变,常量不可变.变量和常量类型可以省略不写,会自动推断。
    • val 不可变变量声明 --> val 变更名 : 变量类型 = 值
    • var 可变变量声明 --> var 变更名 : 变量类型 = 值
    • 一般情况下我们可以不写类型,这样scala会自动判定类型 --> val 变量名 = 值 | var 变量名 = 值
  • Scala中每行后面都会有分号自动推断机制,不用显式写出“;”
  • 建议在Scala中命名使用驼峰命名法

  • 案例
object Test {
  def main(args: Array[String]): Unit = {
    val spark = "hello spark"
    //spark = "haha"  -->  错误,不能给常量再赋值
    println("常量" + spark)
    var helloHadoop = "hello hadoop"
    helloHadoop = "HELLO HADOOP"
    println("变量" + helloHadoop)

    //声明一个数字
    val num: Int = 55
    println("声明一个数字" + num)
    //声明一个字符串
    val word: String = "哈哈"
    println("声明一个字符串" + word)
    //声明一个浮点数
    val fnum: Float = 33.33333333333333f
    println("声明一个浮点数" + fnum)
    val dnum: Double = 33.33333333333333
    println("声明一个浮点数" + dnum)
    //声明一个判断类型
    val flagt: Boolean = true
    val flagf: Boolean = false
    println("声明一个判断类型" + flagt)
    println("声明一个判断类型" + flagf)
  }
}

测试

3 类和对象

  • Scala object相当于java中的单例,object中定义的全是静态的,相当于java中的工具类,Object默认不可以传参,对象要传参,使用apply方法。
  • Scala类中可以传参,传参一定要指定类型,有了参数就有了默认了构造。类中的属性默认有getter和setter方法
  • 类中重载构造时,构造中第一行必须先调用默认的构造 。def this(....){....}
  • Scala中当new class 时,类中除了方法不执行【除了构造方法】,其他都执行。
  • 在同一个scala文件中,class名称和Object名称一样时,这个类叫做个对象的伴生类,这个对象叫做这个类的伴生对象,他们之间可以互相访问私有变量。

  • 案例1
class Person(xname: String, xage: Int) {
  println("******* Person Class Start*******")
  private val name = xname
  var age = xage
  var gender = 'M'

  //观察重载的构造器
  def this(yname: String, yage: Int, ygender: Char) {
    this(yname, yage)
    this.gender = ygender
  }

  //观察object的静态性。直接调用其属性
  def sayName() = {
    println(name + " hello world... " + classAndObj.name)
  }

  println("******* Person Class End*******")
}
//观察伴生对象可以使用私有属性
object Person{
  val p = new Person("zhangsan", 20)
  println("伴生对象:"+p.name)
}

object classAndObj {
  println("******* classAndObj Object *******")
  val name = "wangwu"
  //object要传参需要apply方法
  def apply(i: Int) = {
    println("Score is " + i)
  }
  def apply(i: Int, s: String) = {
    println("name is " + s + ",score is " + i)
  }

  def main(args: Array[String]): Unit = {
    //object要传参需要apply方法
    classAndObj(1000)
    classAndObj(1000, "zhaoliu")

    val p = new Person("zhangsan", 20)
    //println(p.name)不可以直接调用私有属性
    p.sayName()
    println(p.gender)

    val p1 = new Person("lisi", 18, 'F')
    p1.sayName()
    println(p1.gender)
    p1.age = 200
    println(p1.age)
  }
}

测试

  • 案例2
class Person {
  var name: String = _ //未赋值,会生成getter和setter方法
  val age = 10         //只会生成getter方法
  private[this] val gender = "male" //只能在定义里使用,实例也不能调用
}

object ObjTest {
  def main(args: Array[String]): Unit = {
    val p = new Person //括号可省略
    p.name = "zhangsan"
    println(p.name + ":" + p.age)
    //println(p.gender)
  }
}

测试

  • 案例3
class Person(val name : String,val age :Int) {
  //1.参数直接跟在类名后面的是主构造器
  //2.主构造器中的参数最后会被编译成字段
  //3.主构造器在执行的时候会执行类中的所有语句
  //4.假设参数声明时不带val和var,那么相当于private[this]!!!
  println("这是一个主构造器")
}

object ObjTest {
  def main(args: Array[String]): Unit = {
    val p = new Person("zhangsan",15)
    println(p.name + ":" + p.age)
  }
}

测试

  • 案例4
class Person(val name: String, val age: Int) {
  //1.参数直接跟在类名后面的是主构造器
  //2.主构造器中的参数最后会被编译成字段
  //3.主构造器在执行的时候会执行类中的所有语句
  //4.假设参数声明时不带val和var,那么相当于private[this]!!!
  println("这是一个主构造器")
  var gender : String = _
  //1. 附属构造器,名称是this
  //2. 每一个附属构造器必须首先调用已经存在的子构造器或者附属构造器
  def this(name: String, age: Int, gender: String) {
    this(name,age)
    this.gender = gender
  }
}

object ObjTest {
  def main(args: Array[String]): Unit = {
    val p = new Person("zhangsan", 15,"male")
    println(p.name + ":" + p.age + ":" + p.gender)
  }
}

测试

  • 案例5
class Person(val name: String, val age: Int) {
  println("这是一个主构造器")
}

class Student(name: String, age: Int, val major: String) extends Person(name, age) {
  println("这是Person子类的一个主构造器")
}

object ObjTest {
  def main(args: Array[String]): Unit = {
    val s = new Student("zhangsan", 15, "Math")
    print(s.name + ":" + s.age + ":" + s.major)
  }
}

测试

  • 案例6
class Person(val name: String, val age: Int) {
  println("这是一个主构造器")
  val school = "haha"
  def eat(): Unit ={
    println("人吃饭")
  }
}

class Student(name: String, age: Int, val major: String) extends Person(name, age) {
  println("这是Person子类的一个主构造器")
  override val school = "xixi"
  override def toString = "override toString..."
  override def eat(): Unit ={
    println("学生吃饭")
  }
}

object ObjTest {
  def main(args: Array[String]): Unit = {
    val s = new Student("zhangsan", 15, "Math")
    println(s.name + ":" + s.age + ":" + s.major)
    println(s.toString)
    println(s.school)
    s.eat()
  }
}

测试

4 流程控制

4.1 if | else if | else -- 三元 -- for -- while -- do while

  • 案例
object Test {
  def main(args: Array[String]): Unit = {
    //if | else if | else
    val x = 3
    if (x == 1) {
      println("x==1")
    } else if (x == 2) {
      println("x==2")
    } else {
      println("其他情况")
    }
    //三元
    val num = if (x > 0) 1 else 0
    println(num)
    println("*****")
    //while
    var (n, m) = (3, 0)
    while (n > 0) {
      m = m + n
      n = n - 1
    }
    println(m)
    println("*****")
    //do while
    do{
    println(m)
    }while(m<0)
    println("*****")
    //for 1-10
    for (i <- 1 to 10) {
      print(i+"\t")
    }
    println()
    println("*****")
    //for 1-9
    for (i <- 1 until 10) {
      print(i+"\t")
    }
    println()
    println("*****")
    //for 1-9 偶数
    for (i <- 1 until 10 if i % 2 == 0) {
      print(i+"\t")
    }
    println()
    println("*****")
    //操作符函数写法
    println(1.to(10))
    println(1.until(10))
    println(1.until(10,2))
    println("*****")
    //foreach
    val str = "abcd"
    str.foreach(x => print(x+"\t"))
    println()
    str.foreach(print(_))
    println()
    str.foreach(print)
  }
}

测试

4.2 match case

  • 案例
/**
  * Match 模式匹配
  * 1.case _ 什么都匹配不上匹配,放在最后
  * 2.match 可以匹配值还可以匹配类型
  * 3.匹配过程中会有数值的转换
  * 4.从上往下匹配,匹配上之后会自动终止
  * 5.模式匹配外部的“{..}”可以省略
  */
object Test extends App {
  def MatchTest(o: Any) =
    o match {
      case i: Int => println(s"type is Int ,value = $i")
      case 1 => println("value is 1")
      case d: Double => println(s"type is Double ,value = $d")
      case q if q.equals("abc") => println("value is abc")
      case s: String => println(s"type is String ,value = $s")
      case 'a' => println("value is a")
      case _ => {
        println("no match...")
      }
    }

  val tp = (1, 1.2, "abc", 'a', "xx", true)
  val iter: Iterator[Any] = tp.productIterator
  iter.foreach(MatchTest)
}

测试

4.3 偏函数

  • 如果一个方法中没有match 只有case,这个函数可以定义成PartialFunction偏函数。偏函数定义时,不能使用括号传参,默认定义PartialFunction中传入一个值,匹配上了对应的case,返回一个值。
  • 案例
object Test extends App {
  def MyTest : PartialFunction[String,String] = {
    case "scala" =>{"scala"}
    case "hello"=>{"hello"}
    case _=> {"no  match ..."}
  }
  println(MyTest("scala"))
}

测试

4.4 样例类(case classes)

  • 使用了case关键字的类定义就是样例类(case classes),样例类是种特殊的类。实现了类构造参数的getter方法(构造参数默认被声明为val),当构造参数是声明为var类型的,它将帮你实现setter和getter方法。
  • 样例类默认帮你实现了toString,equals,copy和hashCode等方法。
  • 样例类可以new, 也可以不用new
  • 案例1
case class Person1(name: String, age: Int)

object Test extends App {
  val p1 = new Person1("zhangsan", 10)
  val p2 = Person1("lisi", 20)
  val p3 = Person1("wangwu", 30)

  val list = List(p1, p2, p3)
  list.foreach(x => {
    x match {
      case Person1("zhangsan", 10) => println("zhangsan")
      case Person1("lisi", 20) => println("lisi")
      case _ => println("no match")
    }
  })
}

测试

  • 案例2
class Code {
}
case class Book(name:String,author : String){
  //构造器中的每一个类型为val
  //不用new就可以产生对象(调用apply()方法)
}
object Test extends App {
  val hadoop = Book("Hadoop","zhangsan")
  hadoop match {
    case Book(name,author) =>println("this is a Book")
    case _ =>println("unknown")
  }
}

测试

5 方法和函数

  • 案例1
object Test {
  //无返回值函数
  def helloPrintName1(name: String): Unit = {
    println("无返回值函数: " + name)
  }

  //无返回值函数,: Unit 可以省略
  def helloPrintName2(name: String) = {
    println("无返回值函数: " + name)
  }

  //有返回值函数
  def helloName1(name: String): String = {
    return "有返回值函数: " + name
  }

  //有返回值函数,默认最后一句就是返回值,可以省略return
  def helloName2(name: String): String = {
    "有返回值函数: " + name
  }

  //把匿名函数赋值给变量
  val add = (x: Int, y: Int) => x + y

  //柯里化
  def add2(x: Int)(y: Int) = x + y

  //可变参数
  def helloName3(name: String*) = {
    name.foreach(x => print("可变参数: " + x + "\t"))
  }

  //默认参数值
  def helloPrintName4(name: String = "china") = {
    println("默认参数值: " + name)
  }

  def main(args: Array[String]): Unit = {
    helloPrintName1("scala")
    helloPrintName2("scala")
    println(helloName1("scala"))
    println(helloName2("scala"))
    println("把匿名函数赋值给变量", add(1, 2))
    println("柯里化", add2(1)(2))
    helloName3("zhangsan", "lisi", "wangwu")
    println()
    helloPrintName4()
    helloPrintName4("Korean")
  }
}

测试

  • 案例2
import java.util.Date

object Test {

  //递归方法5的阶乘
  def recursive(num: Int): Int = {
    if (num == 1)
      num
    else
      num * recursive(num - 1)
  }

  //偏应用函数
  def log(author: String, date: Date, msg: String) = {
    println(s"$author:date is " + date + ",log is " + msg)
  }
  val date = new Date()
  val author = "Heaton"
  //想要调用log,以上变化的是第三个参数,可以用偏应用函数处理
  val logWithDate = log(author, date, _: String)


  def main(args: Array[String]): Unit = {
    println("递归方法5的阶乘", recursive(5))
    log(author,date, "log1")
    log(author,date, "log2")
    logWithDate("log33")
    logWithDate("log44")
  }
}

测试

  • 案例3高阶函数及柯里化
object Test extends App {
  //函数的参数是函数
  def sum(v1: Int, v2: Int): Int = {
    v1 + v2
  }
  def hightSum(f: (Int, Int) => Int, a: Int, b: Int): Int = {
    f(a, b)
  }
  println("函数的参数是函数", hightSum(sum, 1, 2))
  println("函数的参数是函数->使用匿名函数", hightSum((x: Int, y: Int) => x + y, 2, 2))

  //函数的返回是函数(柯里化就是简写)
  //1,2,3,4相加
  def hightSum2(a: Int, b: Int): (Int, Int) => Int = {
    def f2(v1: Int, v2: Int): Int = {
      v1 + v2 + a + b
    }
    f2
  }
  println("函数的返回是函数" + hightSum2(1, 2)(3, 4))

  //函数的参数是函数,函数的返回是函数
  def hightFun(f: (Int, Int) => Int): (Int, Int) => Int = {
    f
  }
  println("函数的参数是函数" + hightFun(sum)(100, 200))
  println("函数的参数是函数->匿名函数" + hightFun((a, b) => a + b)(200, 200))
  //如果函数的参数在方法体中只使用了一次 那么可以写成_表示
  println("函数的参数是函数->简写" + hightFun(_ + _)(200, 200))

  //柯里化函数
  def currie(a: Int, b: Int)(c: Int, d: Int) = {
    a + b + c + d
  }
  println("柯里化函数" + currie(1, 2)(3, 4))
}

测试

6 集合

6.1 数组

  • 案例
import scala.collection.mutable.ArrayBuffer

object Test extends App {
  /**
    * 创建定长数组两种方式:
    * 1.new Array[String](3)
    * 2.直接Array
    */
  //创建类型为Int 长度为3的数组
  val arr1 = new Array[String](3)
  //创建String 类型的数组,直接赋值
  val arr2 = Array[String]("1", "2", "3")
  //赋值
  arr1(0) = "100"
  arr1(1) = "200"
  arr1(2) = "300"

  /**
    * 遍历两种方式
    */
  print("for循环遍历" + "\t")
  for (i <- arr1) {
    print(i + "\t")
  }
  println()
  print("foreach遍历" + "\t")
  arr1.foreach(x => print(x + "\t"))
  println()
  print("foreach遍历" + "\t")
  arr1.foreach(print)
  println()
  /**
    * 数组的一些常用方法
    */
  //拼接方法
  var arr3 = Array.concat(arr1, arr2)
  print("拼接方法结果:" + "\t")
  arr3.foreach((x) => print(x + "\t"))
  println()
  //初始赋值方法
  print("初始赋值结果:" + "\t")
  var arr4 = Array.fill(3)("hello")
  arr4.foreach((x) => print(x + "\t"))
  println()

  /**
    * 创建二维数组和遍历
    */
  val arr5 = new Array[Array[String]](2)
  arr5(0) = Array("1", "2", "3")
  arr5(1) = Array("4", "5", "6")
  println("二维数组遍历结果:")
  for (i <- 0 until arr5.length) {
    for (j <- 0 until arr5(i).length) {
      print(arr5(i)(j) + "  ")
    }
  }
  println()
  println("二维数组遍历结果:")
  for (i <- 0 until arr5.length; j <- 0 until arr5(i).length) {
    print(arr5(i)(j) + "    ")
  }
  println()
  println("二维数组遍历结果:")
  arr5.foreach { arr => {
    arr.foreach { (x) => print(x + "\t") }
  }
  }
  println()


  /**
    * 可变长度数组的定义
    */
  val arr = ArrayBuffer[String]("a", "b", "c")
  arr.append("hello", "scala") //在元素末尾追加多个元素
  arr.+=("end1", "end2") //在最后追加多个元素
  arr.+=:("start") //在开头添加元素
  print("可变数组遍历" + "\t")
  arr.foreach((x) => print(x + "\t"))
}

测试

  • 常用方法
方法描述
def apply( x: T, xs: T* ): Array[T] 创建指定对象 T 的数组, T 的值可以是 Unit, Double, Float, Long, Int, Char, Short, Byte, Boolean。
def concatT: Array[T] 合并数组
def copy( src: AnyRef, srcPos: Int, dest: AnyRef, destPos: Int, length: Int ): Unit 复制一个数组到另一个数组上。相等于 Java's System.arraycopy(src, srcPos, dest, destPos, length)。
def empty[T]: Array[T] 返回长度为 0 的数组
def iterateT( f: (T) => T ): Array[T] 返回指定长度数组,每个数组元素为指定函数的返回值。
def fillT(elem: => T): Array[T] 返回数组,长度为第一个参数指定,同时每个元素使用第二个参数进行填充。
def fillT( elem: => T ): Array[Array[T]] 返回二数组,长度为第一个参数指定,同时每个元素使用第二个参数进行填充。
def ofDimT: Array[T] 创建指定长度的数组
def ofDimT: Array[Array[T]] 创建二维数组
def ofDimT: Array[Array[Array[T]]] 创建三维数组
def range( start: Int, end: Int, step: Int ): Array[Int] 创建指定区间内的数组,step 为每个元素间的步长
def range( start: Int, end: Int ): Array[Int] 创建指定区间内的数组
def tabulateT(f: (Int)=> T): Array[T] 返回指定长度数组,每个数组元素为指定函数的返回值,默认从 0 开始。
def tabulateT( f: (Int, Int ) => T): Array[Array[T]] 返回指定长度的二维数组,每个数组元素为指定函数的返回值,默认从 0 开始。

6.2 列表List

  • 案例
import scala.collection.mutable.ListBuffer

object Test extends App {
  //创建
  val list = List(1, 2, 3, 4, 5)
  //取出某一个
  println("取出某一个", list(0))
  //遍历
  print("遍历\t")
  list.foreach { x => print(x + "\t") }
  println()
  //filter过滤
  val list1 = list.filter { x => x > 3 }
  print("filter过滤结果\t")
  list1.foreach { x => print(x + "\t") }
  println()

  //count统计个数
  val value = list.count(x => x > 3)
  println("count统计结果:" + value)

  //map
  val nameList = List("hello hadoop", "hello scala", "hello world")
  val mapResult: List[Array[String]] = nameList.map(x => x.split(" "))
  print("map处理结果\t")
  mapResult.foreach(x => print(x.toString + "\t"))
  println()
  print("map处理结果\t")
  mapResult.foreach(x => x.foreach(y => print(y + "\t")))
  println()

  //flatmap
  val flatMapResult: List[String] = nameList.flatMap(x => x.split(" "))
  print("flatmap处理结果\t")
  flatMapResult.foreach(x => print(x.toString + "\t"))
  println()

  /**
    * 可变长list
    */
  val listBuffer: ListBuffer[Int] = ListBuffer[Int](1,2,3,4,5)
  listBuffer.append(6,7,8,9)//追加元素
  listBuffer.+=(10)//在后面追加元素
  listBuffer.+=:(100)//在开头加入元素
  print("可变长list遍历\t")
  listBuffer.foreach(x => print(x.toString + "\t"))
}

测试

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

6.3 集合set

  • 案例1
object Test extends App {
  //创建
  val set1 = Set(1, 2, 3, 4, 4)
  val set2 = Set(1, 2, 5)
  //遍历  set会自动去重
  print("遍历\t")
  set1.foreach(x => print(x + "\t"))
  println()
  print("遍历\t")
  for (s <- set1) {
    print(s + "\t")
  }
  println()

  //交集
  val set3 = set1.intersect(set2)
  print("交集遍历\t")
  set3.foreach(x => print(x + "\t"))
  println()
  val set4 = set1.&(set2)
  print("交集遍历\t")
  set4.foreach(x => print(x + "\t"))
  println()
  //差集
  print("差集遍历\t")
  set1.diff(set2).foreach(x => print(x + "\t"))
  println()
  print("差集遍历\t")
  set1.&~(set2).foreach(x => print(x + "\t"))
  println()
  //子集
  println("是否是子集\t"+set1.subsetOf(set2))

  //最大值
  println("最大值\t"+set1.max)
  //最小值
  println("最小值\t"+set1.min)

  //转成数组,list
  print("转成数组\t")
  set1.toArray.foreach(x => print(x + "\t"))
  println()
  print("转成列表\t")
  set1.toList.foreach(x => print(x + "\t"))
  println()
  //mkString集合所有元素作为字符串显示
  println("集合所有元素作为字符串显示"+set1.mkString)
  println("集合所有元素作为字符串显示分隔符\t"+set1.mkString("\t"))
}

测试

  • 案例2
import scala.collection.mutable
import scala.collection.immutable
object Test extends App {
  /**
    * 可变长Set->scala.collection.mutable.Set
    * 不可变长Set->scala.collection.immutable.Set
    */
  val set1 = mutable.Set[Int](1,2,3,4,5)
  val set2 = immutable.Set[Int](1,2,3,4,5)
  set1.add(100)
  set1.+=(200)
  set1.+=(1,210,300)
  print("可变长set遍历")
  set1.foreach(x=>print(x+"\t"))
  //set2.add(100) 报错
}

测试

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

6.4 map

  • 案例1
object Test extends App {

  val map = Map[String, Int]("a" -> 100, "b" -> 200, ("c", 300), ("c", 400))
  val option1: Option[Int] = map.get("a")
  val option2: Option[Int] = map.get("aa")
  println("从map中取键为a的值\t"+option1)
  println("从map中取键为a的值\t"+option1.get)
  println("从map中取键为aa的值\t"+option2)
  println("从map中取键为aa的值\t"+option2.getOrElse("no value"))

  print("遍历:")
  println(map)
  print("遍历:")
  for (elem <- map) {
    print(elem + "\t")
  }
  println()
  print("遍历键->拿到值:")
  val keys: Iterable[String] = map.keys
  keys.foreach(key => {
    val value = map.get(key).get
    print(s"key = $key ,value = $value\t")
  })
  println()
  print("遍历值:")
  val values: Iterable[Int] = map.values
  values.foreach(x => print(x + "\t"))
  println()

  val map1 = Map[String, Int](("a", 1), ("b", 2), ("c", 3), ("d", 4))
  val map2 = Map[String, Int](("a", 100), ("b", 2), ("c", 300), ("e", 500))
  val result1: Map[String, Int] = map1.++(map2)
  val result2: Map[String, Int] = map1.++:(map2)
  print("合并后的结果:")
  result1.foreach(x => print(x + "\t"))
  println()
  print("合并后的结果:")
  result2.foreach(x => print(x + "\t"))
  println()
}

测试

  • 案例2
import scala.collection.mutable
import scala.collection.immutable

object Test extends App {
  //不可变长map->scala.collection.immutable.Map
  //可变长map->scala.collection.mutable.Map
  val map1 = immutable.Map[String, Int]("a" -> 100, "b" -> 200, ("c", 300), ("c", 400))
  val map2 = mutable.Map[String, Int]()
  //map1.put("hello",100)报错
  map2.put("hello", 100)
  map2.put("world", 200)
  map2.put("hadoop", 200)
  print("可变长map遍历:\t")
  map2.foreach(x => print(x + "\t"))
  println()

  //count
  val countResult = map2.count(p => {
    p._1.equals("hadoop") && p._2 == 200
  })
  println(s"键为hadoop值为200的元素有 $countResult 个")

  //filter
  map2.filter(_._1.equals("world")).foreach(x => println("过滤后的元素", x._1, x._2))

  //contains
  println("是否有键为hello的元素", map2.contains("hello"))

  //exist
  println("符合条件的元素存在么",map2.exists(x => {
    x._1.equals("hadoop")
  }))
}

测试

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

6.5 元组Tuple

  • val tuple = new Tuple(1) 可以使用new
  • val tuple2 = Tuple(1,2) 可以不使用new,也可以直接写成val tuple3 =(1,2,3)
  • 取值用”._XX” 可以获取元组中的值
  • 注意:tuple最多支持22个参数
  • 案例
object Test extends App {
  val tuple1: Tuple1[String] = new Tuple1("hello")
  val tuple2: (String, Int) = new Tuple2("a", 100)
  val tuple3: (Int, Boolean, Char) = new Tuple3(1, true, 'C')
  val tuple4: (Int, Double, String, Boolean) = Tuple4(1, 3.4, "abc", false)
  val tuple6: (Int, Int, Int, Int, Int, String) = (1, 2, 3, 4, 5, "abc")
  val tuple22 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, "abc", 14, 15, 16, 17, 18, 19, 20, 21, 22)
  println("针对2元组的倒转方法" + tuple2.swap)
  val value: String = tuple22._13
  println("取值", value)
  println("输出整个元组" + tuple4)
  print("遍历:\t")
  val iter: Iterator[Any] = tuple6.productIterator
  while (iter.hasNext) {
    print(iter.next() + "\t")
  }
  println()
  print("遍历:\t")
  tuple6.productIterator.foreach(x => print(x + "\t"))
}

测试

7 抽象类

  • 案例
abstract class Person {
  def speak
  val name: String
  var age: Int
}

class Student extends Person {
  val name = "zhangsan"
  var age = 10
  def speak = {
    println("speak!!!")
  }
}

object code extends App {
  val s = new Student
  s.speak
  println(s.name + ":" + s.age)
}

测试

8 Trait特性(能够带有具体实现的接口)

  • 案例1
/**
  * 一个类继承多个trait时,第一个关键字使用 extends,之后使用with
  * trait 不可以传参
  */
trait Read {
  def read(name: String) = {
    println(s"$name is reading...")
  }
}

trait Listen {
  def listen(name: String) = {
    println(s"$name is listening...")
  }
}

class Human() extends Read with Listen {
}

object Test extends App {
  val h = new Human()
  h.read("zhangsan")
  h.listen("lisi")
}

测试

  • 案例2
/**
  * Trait中可以有方法体的实现或者方法体的不实现,类继承了Trait要实现Trait中没有实现的方法
  */
trait IsEquale{
  def isEqu(o:Any):Boolean
  def isNotEqu(o:Any) :Boolean =  !isEqu(o)
}
class Point(xx:Int,xy:Int) extends IsEquale {
  val x = xx
  val y = xy
  override def isEqu(o: Any): Boolean = {
    o.isInstanceOf[Point]&&o.asInstanceOf[Point].x==this.x
  }
}
object Test extends App {
  val p1 = new Point(1,2)
  val p2 = new Point(1,3)
  println(p1.isNotEqu(p2))
}

测试

7 apply()方法 及 静态方法 及 单例

  • 案例1
class ApplyTest{
  def apply() = "Apply"
  def test{
    println("test")
  }
}

object ApplyTest{
  def apply() = new ApplyTest()
}

object Test extends App {
  val a = ApplyTest()//类加()调用了对象的apply()方法
  a.test
  val t = new ApplyTest
  print(t())//对象加()就是调用类的apply()方法
}

测试

  • 案例2
object ApplyTest {
  var count = 0
  def incr: Unit = {
    count = count + 1
  }
}
object Test extends App {
  for (i <- 1 until 10) {
    ApplyTest.incr
  }
  print(ApplyTest.count)
}

测试

8 隐式转换

  • 隐式转换是在Scala编译器进行类型匹配时,如果找不到合适的类型,那么隐式转换会让编译器在作用范围内自动推导出来合适的类型。
  • 1.隐式值与隐式参数
    • 隐式值是指在定义参数时前面加上implicit。隐式参数是指在定义方法时,方法中的部分参数是由implicit修饰【必须使用柯里化的方式,将隐式参数写在后面的括号中】。隐式转换作用就是:当调用方法时,不必手动传入方法中的隐式参数,Scala会自动在作用域范围内寻找隐式值自动传入。
    • 隐式值和隐式参数注意:
      • 1). 同类型的参数的隐式值只能在作用域内出现一次,同一个作用域内不能定义多个类型一样的隐式值。
      • 2). implicit 关键字必须放在隐式参数定义的开头
      • 3). 一个方法只有一个参数是隐式转换参数时,那么可以直接定义implicit关键字修饰的参数,调用时直接创建类型不传入参数即可。
      • 4). 一个方法如果有多个参数,要实现部分参数的隐式转换,必须使用柯里化这种方式,隐式关键字出现在后面,只能出现一次
  • 2.隐式转换函数
    • 隐式转换函数是使用关键字implicit修饰的方法。当Scala运行时,假设如果A类型变量调用了method()这个方法,发现A类型的变量没有method()方法,而B类型有此method()方法,会在作用域中寻找有没有隐式转换函数将A类型转换成B类型,如果有隐式转换函数,那么A类型就可以调用method()这个方法。
    • 隐式转换函数注意:隐式转换函数只与函数的参数类型和返回类型有关,与函数名称无关,所以作用域内不能有相同的参数类型和返回类型的不同名称隐式转换函数。
  • 3.隐式类
    • 使用implicit关键字修饰的类就是隐式类。若一个变量A没有某些方法或者某些变量时,而这个变量A可以调用某些方法或者某些变量时,可以定义一个隐式类,隐式类中定义这些方法或者变量,隐式类中传入A即可。
    • 隐式类注意:
      • 1).隐式类必须定义在类,包对象,伴生对象中。
      • 2).隐式类的构造必须只有一个参数,同一个类,包对象,伴生对象中不能出现同类型构造的隐式类。
  • 案例1
object Test extends App {
  def Student(age: Int)(implicit name: String, i: Int) = {
    println(s"student :$name ,age = $age ,score = $i")
  }

  def Teacher(implicit name: String) = {
    println(s"teacher name is = $name")
  }

  implicit val zs: String = "zhangsan"
  implicit val sr: Int = 100

  Student(18)
  Teacher
}

测试

  • 案例2
class Animal(name: String) {
  def canFly(): Unit = {
    println(s"$name can fly...")
  }
}
class Rabbit(xname: String) {
  val name = xname
}

object Test extends App {
  implicit def rabbitToAnimal(rabbit: Rabbit): Animal = {
    new Animal(rabbit.name)
  }

  val rabbit = new Rabbit("RABBIT")
  rabbit.canFly()
}

测试

  • 案例3
class Rabbit(s: String) {
  val name = s
}

object Test extends App {
  implicit class Animal(rabbit: Rabbit) {
    val tp = "Animal"

    def canFly() = {
      println(rabbit.name + " can fly...")
    }
  }

  val rabbit = new Rabbit("rabbit")
  rabbit.canFly()
  println(rabbit.tp)
}

测试

9 Actor 通讯模型

  • Actor Model是用来编写并行计算或分布式系统的高层次抽象(类似java中的Thread)让程序员不必为多线程模式下共享锁而烦恼,被用在Erlang 语言上, 高可用性99.9999999 % 一年只有31ms 宕机Actors将状态和行为封装在一个轻量的进程/线程中,但是不和其他Actors分享状态,每个Actors有自己的世界观,当需要和其他Actors交互时,通过发送事件和消息,发送是异步的,非堵塞的(fire-andforget),发送消息后不必等另外Actors回复,也不必暂停,每个Actors有自己的消息队列,进来的消息按先来后到排列,这就有很好的并发策略和可伸缩性,可以建立性能很好的事件驱动系统。
  • Actor的特征:
    • ActorModel是消息传递模型,基本特征就是消息传递
    • 消息发送是异步的,非阻塞的
    • 消息一旦发送成功,不能修改
    • Actor之间传递时,自己决定决定去检查消息,而不是一直等待,是异步非阻塞的
  • 什么是Akka
    • Akka 是一个用 Scala 编写的库,用于简化编写容错的、高可伸缩性的 Java 和Scala 的 Actor 模型应用,底层实现就是Actor,Akka是一个开发库和运行环境,可以用于构建高并发、分布式、可容错、事件驱动的基于JVM的应用。使构建高并发的分布式应用更加容易。
    • spark1.6版本之前,spark分布式节点之间的消息传递使用的就是Akka,底层也就是actor实现的。1.6之后使用的netty传输。
  • 案例1
import scala.actors.Actor

class myActor extends Actor {
  def act() {
    while (true) {
      receive {
        case x: String => println("get String =" + x)
        case x: Int => println("get Int")
        case _ => println("get default")
      }
    }
  }
}

object Test extends App {
  //创建actor的消息接收和传递
  val actor = new myActor()
  //启动
  actor.start()
  //发送消息写法
  actor ! "i love you !"
  actor ! 500
  actor ! true
}

测试

  • 案例2 Actor与Actor之间通信
import scala.actors.Actor

case class Message(actor: Actor, msg: Any)

class Actor1 extends Actor {
  def act() {
    while (true) {
      receive {
        case msg: Message => {
          println("i sava msg! = " + msg.msg)
          msg.actor ! "i love you too !"
        }
        case msg: String => println(msg)
        case _ => println("default msg!")
      }
    }
  }
}

class Actor2(actor: Actor) extends Actor {
  actor ! Message(this, "i love you !")

  def act() {
    while (true) {
      receive {
        case msg: String => {
          if (msg.equals("i love you too !")) {
            println(msg)
            actor ! "could we have a date !"
          }
        }
        case _ => println("default msg!")
      }
    }
  }
}

object Test extends App {
  val actor1 = new Actor1()
  actor1.start()
  val actor2 = new Actor2(actor1)
  actor2.start()
}

测试

推荐阅读